ASP.NET Core中基于Redis与gRPC的自定义授权属性实现咨询
解决方案:使用授权处理程序实现自定义Token验证逻辑
选择建议:优先用授权处理程序(IAuthorizationHandler)
ASP.NET Core的授权处理程序是框架原生的授权扩展方式,能完美集成到内置的授权流程中,支持ClaimsPrincipal的构建、授权上下文的传递,后续如果需要结合角色/策略授权会更灵活。而Authorization Filter更偏向请求管道的前置拦截,处理授权逻辑时无法很好地复用框架的授权上下文,扩展性较差,因此不推荐。
具体实现步骤
1. 定义自定义授权需求与属性
先创建关联的授权需求和标记属性,用于在API上标记需要验证Token的接口:
// 自定义授权需求,仅作为标记 public class ValidateTokenRequirement : IAuthorizationRequirement { } // 自定义授权属性,关联上述需求 public class ValidateTokenAttribute : AuthorizeAttribute { public ValidateTokenAttribute() { Policy = nameof(ValidateTokenRequirement); } }
2. 实现授权处理程序
注入gRPC客户端、Redis缓存和HttpContext访问器,完成Token验证、缓存逻辑:
public class ValidateTokenHandler : AuthorizationHandler<ValidateTokenRequirement> { private readonly AuthorizationGrpcServices.AuthorizationGrpcServicesClient _grpcAuthClient; private readonly IDistributedCache _redisCache; private readonly IHttpContextAccessor _httpContextAccessor; public ValidateTokenHandler(AuthorizationGrpcServices.AuthorizationGrpcServicesClient grpcClient, IDistributedCache cache, IHttpContextAccessor httpContextAccessor) { _grpcAuthClient = grpcClient; _redisCache = cache; _httpContextAccessor = httpContextAccessor; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidateTokenRequirement requirement) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) { context.Fail(); return; } // 从请求头提取Token var authHeader = httpContext.Request.Headers.Authorization.FirstOrDefault(); var token = authHeader?.Split(" ").Last(); if (string.IsNullOrEmpty(token)) { context.Fail(); return; } // 先查Redis缓存,避免重复调用gRPC var cacheKey = $"Auth:Token:{token}"; var cachedRoles = await _redisCache.GetStringAsync(cacheKey); if (!string.IsNullOrEmpty(cachedRoles)) { // 构建用户身份信息,添加角色声明 var roleClaims = cachedRoles.Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(r => new Claim(ClaimTypes.Role, r.Trim())); var identity = new ClaimsIdentity(roleClaims, "CustomTokenAuth"); context.User.AddIdentity(identity); context.Succeed(requirement); return; } // 调用gRPC验证Token var grpcResponse = await _grpcAuthClient.ValidateTokenAsync(new ValidateTokenRequest { Token = token }); if (!grpcResponse.Access) { context.Fail(); return; } // 将验证结果存入Redis,过期时间建议与Token有效期一致 await _redisCache.SetStringAsync(cacheKey, grpcResponse.Roles, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) // 按需调整 }); // 构建用户身份信息,完成授权 var validRoleClaims = grpcResponse.Roles.Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(r => new Claim(ClaimTypes.Role, r.Trim())); var validIdentity = new ClaimsIdentity(validRoleClaims, "CustomTokenAuth"); context.User.AddIdentity(validIdentity); context.Succeed(requirement); } }
3. 注册服务到DI容器
在API的Program.cs中注册gRPC客户端、Redis缓存和授权相关服务:
// 注册gRPC客户端 builder.Services.AddGrpcClient<AuthorizationGrpcServices.AuthorizationGrpcServicesClient>(options => { options.Address = new Uri("https://your-identity-server-grpc-url"); // 替换为你的Identity Server gRPC地址 }); // 注册Redis缓存 builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "your-redis-connection-string"; // 替换为你的Redis连接字符串 }); // 配置授权策略 builder.Services.AddAuthorization(options => { options.AddPolicy(nameof(ValidateTokenRequirement), policy => policy.Requirements.Add(new ValidateTokenRequirement())); }); // 注册授权处理程序和HttpContext访问器 builder.Services.AddScoped<IAuthorizationHandler, ValidateTokenHandler>(); builder.Services.AddHttpContextAccessor();
4. 在API接口上使用自定义授权属性
直接在需要验证Token的控制器或Action上标记[ValidateToken]:
[ApiController] [Route("api/[controller]")] public class DemoController : ControllerBase { [HttpGet("protected")] [ValidateToken] public IActionResult GetProtectedData() { var userRoles = User.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value); return Ok($"当前用户角色:{string.Join(", ", userRoles)}"); } }
注意事项
- Redis缓存的过期时间建议与JWT Token的有效期保持一致,避免缓存的角色信息过期后Token仍有效
- 需添加异常处理逻辑(如gRPC调用失败、Redis连接异常),可根据业务需求实现重试或降级策略
- 如果Token是自包含JWT,可先本地验证签名,再调用gRPC验证Token是否被吊销,进一步减少gRPC调用次数
内容的提问来源于stack exchange,提问作者Regestea
相关产品推荐
相关产品推荐

