我正在尝试将我的身份验证内容迁移到Core 2.0并使用我自己的身份验证方案遇到问题。我在启动时的服务设置如下所示:
var authenticationBuilder = services.AddAuthentication(options =>
{
options.AddScheme("myauth", builder =>
{
builder.HandlerType = typeof(CookieAuthenticationHandler);
});
})
.AddCookie();
我在控制器中的登录代码如下所示:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Name)
};
var props = new AuthenticationProperties
{
IsPersistent = persistCookie,
ExpiresUtc = DateTime.UtcNow.AddYears(1)
};
var id = new ClaimsIdentity(claims);
await HttpContext.SignInAsync("myauth", new ClaimsPrincipal(id), props);
但是当我在控制器或动作过滤器中时,我只有一个身份,并且它不是经过身份验证的身份:
var identity = context.HttpContext.User.Identities.SingleOrDefault(x => x.AuthenticationType == "myauth");
导航这些变化一直很困难,但我猜我正在做.AddScheme错了。有什么建议吗?
编辑:这里(基本上)是一个干净的应用程序,不会在User.Identies上产生两组身份:
namespace WebApplication1.Controllers
{
public class Testy : Controller
{
public IActionResult Index()
{
var i = HttpContext.User.Identities;
return Content("index");
}
public async Task<IActionResult> In1()
{
var claims = new List<Claim> { new Claim(ClaimTypes.Name, "In1 name") };
var props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };
var id = new ClaimsIdentity(claims);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id), props);
return Content("In1");
}
public async Task<IActionResult> In2()
{
var claims = new List<Claim> { new Claim(ClaimTypes.Name, "a2 name") };
var props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };
var id = new ClaimsIdentity(claims);
await HttpContext.SignInAsync("a2", new ClaimsPrincipal(id), props);
return Content("In2");
}
public async Task<IActionResult> Out1()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Content("Out1");
}
public async Task<IActionResult> Out2()
{
await HttpContext.SignOutAsync("a2");
return Content("Out2");
}
}
}
启动:
namespace WebApplication1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie("a2");
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
答案 0 :(得分:18)
导航这些变化一直很困难,但我猜测我正在做.AddScheme错误。
不要使用AddScheme
:它是为处理程序编写者设计的低级方法。
如何在ASP.NET Core 2.0中设置多个身份验证方案?
要注册cookie处理程序,只需执行以下操作:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = "myauth1";
})
.AddCookie("myauth1");
.AddCookie("myauth2");
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
// ...
}
}
重要的是要注意,您不能像在1.x中那样注册多个默认方案(这个巨大的重构的重点是避免同时拥有多个自动身份验证中间件)
如果您绝对需要在2.0中模拟此行为,则可以编写自定义中间件,手动调用AuthenticateAsync()
并创建包含所需身份的ClaimsPrincipal
:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = "myauth1";
})
.AddCookie("myauth1");
.AddCookie("myauth2");
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.Use(async (context, next) =>
{
var principal = new ClaimsPrincipal();
var result1 = await context.AuthenticateAsync("myauth1");
if (result1?.Principal != null)
{
principal.AddIdentities(result1.Principal.Identities);
}
var result2 = await context.AuthenticateAsync("myauth2");
if (result2?.Principal != null)
{
principal.AddIdentities(result2.Principal.Identities);
}
context.User = principal;
await next();
});
// ...
}
}
答案 1 :(得分:17)
另一种可能性是在运行时确定选择哪种身份验证策略方案,在这种情况下,我可以使用http身份验证承载令牌标头或cookie。
因此,感谢https://github.com/aspnet/Security/issues/1469
JWT令牌(如果在请求标头中有),然后是OpenIdConnect(Azure AD)或其他任何内容。
public void ConfigureServices(IServiceCollection services)
{
// Add CORS
services.AddCors();
// Add authentication before adding MVC
// Add JWT and Azure AD (that uses OpenIdConnect) and cookies.
// Use a smart policy scheme to choose the correct authentication scheme at runtime
services
.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = "smart";
sharedOptions.DefaultChallengeScheme = "smart";
})
.AddPolicyScheme("smart", "Authorization Bearer or OIDC", options =>
{
options.ForwardDefaultSelector = context =>
{
var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
if (authHeader?.StartsWith("Bearer ") == true)
{
return JwtBearerDefaults.AuthenticationScheme;
}
return OpenIdConnectDefaults.AuthenticationScheme;
};
})
.AddJwtBearer(o =>
{
o.Authority = Configuration["JWT:Authentication:Authority"];
o.Audience = Configuration["JWT:Authentication:ClientId"];
o.SaveToken = true;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddAzureAd(options => Configuration.Bind("AzureAd", options));
services
.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
// Authentication is required by default
config.Filters.Add(new AuthorizeFilter(policy));
config.RespectBrowserAcceptHeader = true;
});
...
}
答案 2 :(得分:2)
https://stackoverflow.com/a/51897159/4425154的解决方案有帮助。首先要考虑的几个问题,
如果您使用的是中间件,请确保您遵循以下提及的授权策略
<div class="step-1-wrapper steps ">
<div class="step-1-inner">
<div class="step-1-icon-wrap anim-step-1" >
<svg class="circular-chart orange step-1-circle">
<line stroke-dasharray="5, 5" x1="250" y1="255" x2="330" y2="255" class="step-1-2-line-mvr"></line>
<line x1="250" y1="255" x2="330" y2="255" class="step-1-2-line-mvr-anim"></line>
<path class="circle-bg" d="M165 170
a 85 85 0 0 1 0 170
a 85 85 0 0 1 0 -170"></path>
<path class="anim-circle" d="M165 170
a 85 85 0 0 1 0 170
a 85 85 0 0 1 0 -170"></path>
</svg>
</div>
</div>
</div>
.steps {
display: inline-block;
width: 24%;
vertical-align: middle;
text-align: center;
margin-right: -2px;
margin-left: -2px;
}
.step-1-icon-wrap {
height: 155px;
width: 155px;
background-color: #ffffff;
border-radius: 100%;
-webkit-box-shadow: 0px 0px 10px 0px rgba(26,122,171,0.25);
-moz-box-shadow: 0px 0px 10px 0px rgba(26,122,171,0.25);
box-shadow: 0px 0px 10px 0px rgba(26,122,171,0.25);
margin: 0 auto;
margin-left: 30px;
}
.circular-chart {
position: absolute;
height: 100%;
width: 100%;
left: -57px;
top: 3px;
}
.anim-circle {
fill: transparent;
stroke: #f8fcff;
stroke-width: 3;
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.anim-circle {
fill: transparent;
stroke: #f8fcff;
stroke-width: 3;
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.circle-bg {
fill: none;
stroke: #57c1f8;
stroke-width: 2;
stroke-dasharray: 6;
}
.step-1-2-line-mvr {
stroke: #57c1f8;
stroke-width: 2;
}
.step-1-2-line-mvr-anim {
stroke: #f8fcff;
stroke-width: 3;
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
.anim-step-1 .step-1-2-line-mvr-anim {
animation: dash 3s linear 1.5s normal 1;
}
.anim-step-1 .anim-circle {
animation: dash 3s linear 1s normal 1;
}
.step-1-inner{
position: relative;
min-height: 430px;
padding-top: 180px;
}
@keyframes dash {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: 1000;
}
}
答案 3 :(得分:1)
//******Startup=>ConfigureServices******
services.AddAuthentication(option =>
{
option.DefaultScheme = "AdministratorAuth";
})
.AddCookie("AdministratorAuth", "AdministratorAuth", option =>
{
option.Cookie.Name = "AdministratorAuth";
option.LoginPath = new PathString("/AdminPanel/Login");
option.ExpireTimeSpan = TimeSpan.FromMinutes(14400);
option.AccessDeniedPath = "/Error/UnAuthorized";
option.LogoutPath = "/Security/Logout";
})
.AddCookie("UsersAuth", "UsersAuth", option =>
{
option.Cookie.Name = "UsersAuth";
option.LoginPath = new PathString("/Security/LoginUser/");
option.ExpireTimeSpan = TimeSpan.FromMinutes(144000);
option.AccessDeniedPath = "/Error/UnAuthorized";
option.LogoutPath = "/Security/LogoutUser";
});
//______________________________________________________________
//******Startup=> Configure******
app.UseAuthentication();
app.UseCookiePolicy();
//______________________________________________________________
//******Admin Login******
var status = HttpContext.SignInAsync("AdministratorAuth", new ClaimsPrincipal(principal), properties)IsCompleted;
//******OtherUsers Login******
var status = HttpContext.SignInAsync("UsersAuth", new ClaimsPrincipal(principal), properties)IsCompleted;
//______________________________________________________________
[Authorize(AuthenticationSchemes = "AdministratorAuth")]
public class DashboardController : BaseController
{
}
答案 4 :(得分:0)
万一有人需要解决方案,这就是我所做的:
services.AddMvc(options =>
{
var defaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(IdentityServerAuthenticationDefaults.AuthenticationScheme, BasicAuthenticationDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(defaultPolicy));
});
services.AddAuthentication()
.AddIdentityServerAuthentication(option config here)
.AddBasicAuthentication(setting);
答案 5 :(得分:0)
扩展@HotN 解决方案 如果使用 Blazor 服务器 和 AddDefaultIdentity 和 Blazor Wasm JwtBearer
services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = "smart";
opt.DefaultChallengeScheme = "smart";
})
.AddPolicyScheme("smart", "Authorization Bearer or OIDC", options =>
{
options.ForwardDefaultSelector = context =>
{
var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
if (authHeader?.ToLower().StartsWith("bearer ") == true)
{
return JwtBearerDefaults.AuthenticationScheme;
}
return IdentityConstants.ApplicationScheme;
};
})
.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["ValidIssuer"],
ValidAudience = jwtSettings["ValidAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["securityKey"])),
};
});