【问题标题】:How to ConfigureServices Authentication based on routes in ASP.NET Core 2.0如何在 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());

【问题讨论】:

标签: authentication asp.net-core asp.net-core-mvc


【解决方案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>();
    

    【讨论】:

    • 微软有没有关于这个功能的文档?看起来很方便;很惊讶我在文档网站上看不到任何东西。基于路径中唯一的客户名称,我们有不同的安全要求。能够根据他们的配置动态地将人们路由到正确的身份验证提供程序对于该用例非常有用。
    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 2018-03-30
    • 2018-06-23
    • 2018-01-30
    • 1970-01-01
    • 2018-01-23
    相关资源
    最近更新 更多