如何在 ASP.NET Core 2.0 中设置多个身份验证方案?
Posted
技术标签:
【中文标题】如何在 ASP.NET Core 2.0 中设置多个身份验证方案?【英文标题】:How do I setup multiple auth schemes in ASP.NET Core 2.0? 【发布时间】:2018-01-23 12:34:16 【问题描述】:我正在尝试将我的身份验证内容迁移到 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?");
);
【问题讨论】:
我们按照 IdentityServer4 快速入门中的这个示例注册了我们的方案:github.com/IdentityServer/IdentityServer4.Samples/blob/release/… 这与 Core 2.0 无关。 【参考方案1】:2019 年 12 月的编辑:请先考虑这个答案: Use multiple JWT Bearer Authentication
我的旧答案(不适合使用多个 JWT,而只适合使用 JWT + API 密钥,正如用户评论的那样):
另一种可能性是在运行时确定要选择哪种身份验证策略方案,我曾遇到过可以拥有 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;
);
...
编辑于 07/2019:我必须添加一个指向以下提案的链接,因为它也很有帮助:您可能不会像我一样在 AddAuthentication()
中使用参数,因为这会设置默认方案。一切都在这里得到很好的解释:
Use multiple JWT Bearer Authentication。
我真的很喜欢这种另一种方法!
【讨论】:
我尝试了上面的代码,但收到错误Process is terminating due to ***Exception
(DotNet Core 2.2)。如果提供了令牌,我想使用 JWT,否则 openid 连接。
这种方法还不错,发生的情况是两种身份验证机制总是被触发,实际上你引用的url以更好的方式面对这个,实际上我找不到一种方法来选择性地通过在 Authorize 属性中指定 Scheme 似乎被忽略了,我实现它的唯一方法是在 [Authorize] 中指定策略,并且在策略定义中指定 Scheme。
您确定两个处理程序都使用此配置运行吗?我已经尝试实现上述内容,并且仅在我的情况下运行相关的处理程序。另一方面,链接的解决方案每次都运行。奇怪的。也许是因为它们都是 JWT,而我用它来解决使用 Bearer 或 API 密钥的问题。
感谢@barbara.post!
芭芭拉,你的技术很好,即使有参数。 @john-reilly 在他的“使用 ASP.NET Core 的双启动身份验证”博文中解释了如何:blog.johnnyreilly.com/2020/03/…【参考方案2】:
浏览这些更改很困难,但我猜我做错了 .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();
);
// ...
【讨论】:
我建立了一个干净的项目并使用了上面的代码,然后创建了登录方法(类似于我的问题中的代码),但它不起作用。 User.Identities 上只有一个身份,它是与默认值关联的身份。另外,奇怪的是,它的 IsAuthenticated 属性是假的。 如果没有看到完整的应用程序,很难说出问题所在。考虑更新您的问题以包含详细的 ASP.NET Core 日志。这肯定会有所帮助。 我在上面添加了代码......这就是整个应用程序。如果我调试,然后点击 /testy/in1 然后点击 /testy/in2,然后返回 /testy 并在 Index() 的第一行放置一个断点,只有一个标识。不确定您想查看哪些日志。 正如我所说,这是现在 2.0 中的预期行为,每个应用程序只能有一个默认处理程序(因此,每个请求只有一个身份)。考虑使用[Authorize(AuthenticationSchemes = "myauth1")]
或[Authorize(AuthenticationSchemes = "myauth2")]
装饰您的操作,以便为每个操作选择正确的身份。
答案已更新以包含自定义中间件示例。【参考方案3】:
https://***.com/a/51897159/4425154 的解决方案有帮助。在提到的解决方案之上要考虑几个项目,
-
确保您使用的是 .net core run-time 2.1 或更高版本
如果您使用中间件,请确保您的授权策略如下所述
services.AddMvc(options =>
var defaultPolicy = new AuthorizationPolicyBuilder(new[] CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme )
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(defaultPolicy));
)
【讨论】:
在 dotnet 核心上进行设置的方法多么复杂。天哪.. 谢谢你的回答。【参考方案4】:如果有人需要解决方案,这就是我所做的:
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】://******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
【讨论】:
【参考方案6】:扩展@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"])),
;
);
【讨论】:
以上是关于如何在 ASP.NET Core 2.0 中设置多个身份验证方案?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ASP.NET Core 中设置 cookie validateInterval?