首页 > 解决方案 > 如何为所有 API 方法创建具有不同身份验证的路由

问题描述

我有一个基于 ASP .NET core 2.2 的 Web API 项目。此 API 项目使用 JWT 身份验证。现在,我不仅需要使用以前的 JWT 身份验证,还需要使用 AzureADB2C JWT Token 进行身份验证。无论使用何种身份验证方法,都可以访问相同的控制器和方法。

这就是我目前实现功能的方式

var defaultSchemes = new[] { JwtBearerDefaults.AuthenticationScheme, AzureADB2CDefaults.BearerAuthenticationScheme };
var policy = new AuthorizationPolicyBuilder(defaultSchemes)
                .RequireAuthenticatedUser()
                .Build();

services.AddMvc(config =>
{
    config.Filters.Add(new AuthorizeFilter(policy));
});

services
    .AddAuthentication()
    //.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options)); <-- this works only if it is placed before the AddJwtBearer method, I don't understand why
    .AddJwtBearer(configureOptions =>
        {
            configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
            configureOptions.TokenValidationParameters = tokenValidationParameters;
            configureOptions.SaveToken = true;
        })
    .AddJwtBearer(AzureADB2CDefaults.BearerAuthenticationScheme, configureOptions =>
        {
            configureOptions.Authority = Configuration["AzureAdB2C:Instance"] + Configuration["AzureAdB2C:Domain"] + "/" + Configuration["AzureAdB2C:SignUpSignInPolicyId"] + "/v2.0";
            configureOptions.Audience = Configuration["AzureAdB2C:ClientId"];               
        });

这有效,但不完全符合我的意愿。事实上,请求中传递的令牌使用两种身份验证方法进行验证,结果在文件日志中,对于调用的每个 api 方法,两种身份验证方法之一都会产生验证错误。

我希望所有 api 方法都有 2 个端点,一个使用标准 JWT 身份验证,另一个使用 AzureADB2C。

例子:

http://apiurl/culture/jwt/controller/action --> 用于标准 JWT 身份验证 http://apiurl/culture/b2c/controller/action --> 用于 ADB2c 身份验证

或者

http://apiurl/jwt/culture/controller/action --> 用于标准 JWT 身份验证 http://apiurl/b2c/culture/controller/action --> 用于 ADB2c 身份验证

我该如何做到这一点,或者使这两种身份验证方法对所有 API 共存的最佳方法是什么?

编辑:我发现这个类似的问题有一个有效的答案:ASP.NET Core MVC 2.0 中的基于路径的身份验证 除了答案中给出的解决方案之外,我添加了这个类以不编辑每个控制器的路由。

public class AuthenticationConvention : IApplicationModelConvention
{
    public void Apply(ApplicationModel application)
    {
        var authenticationPrefix = new AttributeRouteModel(new RouteAttribute("{authentication}"));

        foreach (var controller in application.Controllers)
        {
            var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList();
            if (matchedSelectors.Any())
            {
                foreach (var selectorModel in matchedSelectors)
                {
                    selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(authenticationPrefix, selectorModel.AttributeRouteModel);
                }
            }

            var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList();
            if (unmatchedSelectors.Any())
            {
                foreach (var selectorModel in unmatchedSelectors)
                {
                    selectorModel.AttributeRouteModel = authenticationPrefix;
                }
            }
        }
    }
}

并在 Startup.cs 的 ConfigureService 方法中

var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();

services.AddMvc(config =>
{
    // Set the authentication and culture convention for all controllers, so you do not have to specify in the route for each controller
    config.Conventions.Insert(0, new LocalizationConvention());
    config.Conventions.Insert(1, new AuthenticationConvention());
    // -----Authorization filter
    config.Filters.Add(new AuthorizeFilter(policy));
});

有没有更好的方法来做我需要的事情?

此外,我仍然不明白为什么,使用这段代码它可以工作:

services
.AddAuthentication()
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options))
.AddJwtBearer(configureOptions =>
    {
        configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
        configureOptions.TokenValidationParameters = tokenValidationParameters;
        configureOptions.SaveToken = true;
    });

但是这一点,ADB2C 身份验证不起作用:

services
.AddAuthentication()    
.AddJwtBearer(configureOptions =>
    {
        configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
        configureOptions.TokenValidationParameters = tokenValidationParameters;
        configureOptions.SaveToken = true;
    })
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

标签: apiauthenticationroutesazure-ad-b2casp.net-core-2.2

解决方案


推荐阅读