如何在 ASP.NET Core 2.0 中根据路由配置服务身份验证

Posted

技术标签:

【中文标题】如何在 ASP.NET Core 2.0 中根据路由配置服务身份验证【英文标题】:How to ConfigureServices Authentication based on routes in ASP.NET Core 2.0 【发布时间】:2018-03-09 22:06:40 【问题描述】:

在 ASP.NET Core 1.x 中,我可以在 Configure 中使用身份验证方法,但现在在 ASP.NET Core 2.0 中,我必须在 ConfigureServices 并且无法在 Configure 方法中进行配置。例如

public void ConfigureServices(IServiceCollection services)

    services.AddAuthentication()
            .AddCookie()
            .AddXX();

然后在

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    ....
    app.UseAuthentication();

在过去,我可以使用类似的东西

app.UseOpenIdConnectAuthentication();

我不能再这样配置了。

那么我现在如何在 ASP.NET Core 2.0 中使用这样的东西?

app.Map(new PathString("/MyPath"), i => i.UseMyAuthMethod());

【问题讨论】:

我在 github github.com/aspnet/Security/issues/1479#issuecomment-360928524找到了微软人的答案 【参考方案1】:

Microsoft docs 说明如果您想在 ASP.NET Core 2+ 中使用多种身份验证方案该怎么做:

下面的例子可以在每一个上动态选择方案 请求依据。也就是cookies和API认证如何混用:

public void ConfigureServices(IServiceCollection services)

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
        
            // For example, can foward any requests that start with /api 
            // to the api scheme.
            options.ForwardDefaultSelector = ctx => 
               ctx.Request.Path.StartsWithSegments("/api") ? "Api" : null;
        )
        .AddYourApiAuth("Api");

示例:

我必须实现一个混合身份验证解决方案,其中我需要对某些请求进行 Cookie 身份验证,对其他请求进行令牌身份验证。这是我的样子:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    
        // if URL path starts with "/api" then use Bearer authentication instead
        options.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme : null;
    )
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
        
            o.TokenValidationParameters.ValidateIssuerSigningKey = true;
            o.TokenValidationParameters.IssuerSigningKey = symmetricKey;
            o.TokenValidationParameters.ValidAudience = JwtSignInHandler.TokenAudience;
            o.TokenValidationParameters.ValidIssuer = JwtSignInHandler.TokenIssuer;
        );

JWT Bearer 身份验证实现为described in this answer。

提示:

对我来说最大的“陷阱”之一是:即使 Cookies 策略将 URL 以“/api”开头的请求转发到 Bearer 策略,经过 cookie 验证的用户仍然可以访问这些 URL如果您使用的是 [Authorize] 注释。如果您希望仅通过 Bearer 身份验证访问这些 URL,则必须在 API 控制器/操作上使用 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 注释。

【讨论】:

【参考方案2】:

在 2.0 中,执行每个路由身份验证的最佳选择是使用自定义 IAuthenticationSchemeProvider

public class CustomAuthenticationSchemeProvider : AuthenticationSchemeProvider

    private readonly IHttpContextAccessor httpContextAccessor;

    public CustomAuthenticationSchemeProvider(
        IHttpContextAccessor httpContextAccessor,
        IOptions<AuthenticationOptions> options)
        : base(options)
    
        this.httpContextAccessor = httpContextAccessor;
    

    private async Task<AuthenticationScheme> GetRequestSchemeAsync()
    
        var request = httpContextAccessor.HttpContext?.Request;
        if (request == null)
        
            throw new ArgumentNullException("The HTTP request cannot be retrieved.");
        

        // For API requests, use authentication tokens.
        if (request.Path.StartsWithSegments("/api"))
        
            return await GetSchemeAsync(OAuthValidationDefaults.AuthenticationScheme);
        

        // For the other requests, return null to let the base methods
        // decide what's the best scheme based on the default schemes
        // configured in the global authentication options.
        return null;
    

    public override async Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultAuthenticateSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultChallengeSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultForbidSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultForbidSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultSignInSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultSignInSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultSignOutSchemeAsync();

不要忘记在 DI 容器中注册它(理想情况下,作为单例):

// IHttpContextAccessor is not registered by default
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();

【讨论】:

微软有没有关于这个功能的文档?看起来很方便;很惊讶我在文档网站上看不到任何东西。基于路径中唯一的客户名称,我们有不同的安全要求。能够根据他们的配置动态地将人们路由到正确的身份验证提供程序对于该用例非常有用。

以上是关于如何在 ASP.NET Core 2.0 中根据路由配置服务身份验证的主要内容,如果未能解决你的问题,请参考以下文章

在控制器中更改 ASP.NET Core 2.0 标识连接字符串

如何在 ASP.NET Core 2.0 Razor 页面中填充下拉列表

ASP.Net Core 2.0 如何获取中间件中的所有请求标头? [复制]

如何使用 Url.Action 在 asp.net core 2.0 razor 页面中传递多个操作

ApplicationUser在Asp.Net Core 2.0中的ActionFilter中?

如何在 asp.net core 2.0 中允许具有不同发行者的多个 JWT