api - 如何为所有 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));
解决方案
推荐阅读
- python - StringIO在哪里分配内存
- html - 如何将水平条转换为响应式?
- reactjs - 当我按住以拖动反应原生地图时,谷歌地图标记移动错误
- c# - C# 丢弃是否有任何性能优势?
- ruby - 扎实的 Rubyist - 语法问题 - 可选参数或哈希参数
- azure - Azure App Services 在访问需要身份验证的 Web api 终结点时收到 401。但在本地工作
- snowflake-cloud-data-platform - 如何从 Mac 上的 bash 脚本调用 ./snowsql 文件?
- scala - 如何在scala中使用线程安全异步包装器包装库异步方法?
- r - 在R中如何填写没有出现在序列中的数字?
- machine-learning - 预测电影评分时使用演员的最佳方式