ASP.NET Core同端点如何按认证架构选不同授权策略及相关问题
ASP.NET Core 6.0 双JWT认证的按需授权方案
一、配置双JWT认证方案
首先在Program.cs中注册两个独立的JWT认证方案,分别命名为jwt1和jwt2,配置各自的授权服务器地址、受众等参数:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer("jwt1", options => { options.Authority = "https://your-jwt1-issuer.com"; options.Audience = "your-jwt1-audience"; // 其他JWT验证配置(比如签名算法、时钟偏差等) }) .AddJwtBearer("jwt2", options => { options.Authority = "https://your-jwt2-issuer.com"; options.Audience = "your-jwt2-audience"; // 其他JWT验证配置 });
二、实现按认证方案匹配授权策略
默认的[Authorize]属性会同时校验所有指定策略,无法实现“用哪个方案认证就用对应策略”的逻辑,我们需要自定义授权逻辑:
1. 自定义授权属性
创建一个继承自AuthorizeAttribute的自定义属性,用于绑定认证方案和对应的策略映射,并指定允许的认证方案:
public class AuthorizeBySchemeAttribute : AuthorizeAttribute { public Dictionary<string, string> SchemePolicyMap { get; set; } = new(); public AuthorizeBySchemeAttribute() { // 让认证中间件尝试jwt1或jwt2任一方案 AuthenticationSchemes = "jwt1,jwt2"; } }
2. 实现授权处理程序
编写IAuthorizationHandler实现类,根据当前用户的认证方案匹配对应的策略并校验:
public class SchemeBasedAuthorizationHandler : IAuthorizationHandler { private readonly IAuthorizationPolicyProvider _policyProvider; private readonly IAuthorizationService _authorizationService; public SchemeBasedAuthorizationHandler(IAuthorizationPolicyProvider policyProvider, IAuthorizationService authorizationService) { _policyProvider = policyProvider; _authorizationService = authorizationService; } public async Task HandleAsync(AuthorizationHandlerContext context) { // 获取当前用户使用的认证方案 var authScheme = context.User.Identities.FirstOrDefault()?.AuthenticationType; if (string.IsNullOrEmpty(authScheme)) { context.Fail(); return; } // 获取端点上的自定义授权属性 var authorizeAttr = context.Resource as EndpointMetadataCollection? ?.GetMetadata<AuthorizeBySchemeAttribute>(); if (authorizeAttr == null || !authorizeAttr.SchemePolicyMap.TryGetValue(authScheme, out var policyName)) { context.Fail(); return; } // 获取并校验对应策略 var policy = await _policyProvider.GetPolicyAsync(policyName); if (policy == null) { context.Fail(); return; } var authResult = await _authorizationService.AuthorizeAsync(context.User, context.Resource, policy); if (authResult.Succeeded) { context.Succeed(context.Requirements.First()); } else { context.Fail(); } } }
3. 注册策略与处理程序
在Program.cs中注册自定义授权策略和处理程序:
builder.Services.AddAuthorization(options => { // 配置jwt1对应的授权策略 options.AddPolicy("jwt1_policy", policy => { policy.RequireClaim("role", "admin"); // 示例:要求role声明为admin }); // 配置jwt2对应的授权策略 options.AddPolicy("jwt2_policy", policy => { policy.RequireClaim("permission", "api_access"); // 示例:要求permission声明为api_access }); }); // 注册自定义授权处理程序 builder.Services.AddScoped<IAuthorizationHandler, SchemeBasedAuthorizationHandler>();
4. 端点使用示例
在API端点上应用自定义属性,绑定方案与策略:
[ApiController] [Route("api/test")] public class TestController : ControllerBase { [HttpGet] [AuthorizeByScheme(SchemePolicyMap = new Dictionary<string, string> { {"jwt1", "jwt1_policy"}, {"jwt2", "jwt2_policy"} })] public IActionResult GetData() { return Ok("授权通过"); } }
三、实现JWT1专属的Scope校验
要实现“仅通过jwt1认证时才校验Scope”的逻辑,我们可以自定义授权要求和处理程序:
1. 自定义Scope授权要求
创建一个包含目标Scope的授权要求:
public class Jwt1RequiredScopeRequirement : IAuthorizationRequirement { public string RequiredScope { get; } public Jwt1RequiredScopeRequirement(string requiredScope) { RequiredScope = requiredScope; } }
2. 实现Scope授权处理程序
编写处理程序,仅当用户通过jwt1认证时才校验Scope:
public class Jwt1ScopeAuthorizationHandler : AuthorizationHandler<Jwt1RequiredScopeRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, Jwt1RequiredScopeRequirement requirement) { // 非jwt1认证直接跳过校验 var authScheme = context.User.Identities.FirstOrDefault()?.AuthenticationType; if (authScheme != "jwt1") { context.Succeed(requirement); return Task.CompletedTask; } // 读取Token中的scope声明并校验 var scopeClaimValue = context.User.FindFirst("scope")?.Value; if (string.IsNullOrEmpty(scopeClaimValue)) { context.Fail(); return Task.CompletedTask; } var scopes = scopeClaimValue.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (scopes.Contains(requirement.RequiredScope)) { context.Succeed(requirement); } else { context.Fail(); } return Task.CompletedTask; } }
3. 注册与使用
在Program.cs中注册处理程序,并可以创建自定义属性简化使用:
// 注册Scope授权处理程序 builder.Services.AddScoped<IAuthorizationHandler, Jwt1ScopeAuthorizationHandler>(); // 注册包含Scope要求的策略(可选) builder.Services.AddAuthorization(options => { options.AddPolicy("jwt1_read_scope", policy => { policy.Requirements.Add(new Jwt1RequiredScopeRequirement("read")); }); }); // 自定义Scope属性(可选) public class Jwt1RequiredScopeAttribute : AuthorizeAttribute { public Jwt1RequiredScopeAttribute(string scope) { Policy = $"jwt1_{scope}_scope"; } }
4. 端点使用示例
在需要Scope校验的端点上同时应用两个属性:
[HttpGet("scoped-data")] [AuthorizeByScheme(SchemePolicyMap = new Dictionary<string, string> { {"jwt1", "jwt1_policy"}, {"jwt2", "jwt2_policy"} })] [Jwt1RequiredScope("read")] // 或者直接用[Authorize(Policy = "jwt1_read_scope")] public IActionResult GetScopedData() { return Ok("JWT1认证且Scope校验通过,或JWT2认证通过"); }
内容的提问来源于stack exchange,提问作者Shaheer
相关产品推荐
相关产品推荐

