.NET 7 Web API:如何为AddJwtBearer的ISecurityTokenValidator注入依赖
解决方案
1. 修正自定义JWT验证器代码
先修复MyJwtSecurityTokenHandler中的错误实现,确保核心接口方法正常工作,并优化验证逻辑:
public class MyJwtSecurityTokenHandler : ISecurityTokenValidator { private int _maxTokenSizeInBytes = TokenValidationParameters.DefaultMaximumTokenSizeInBytes; private readonly JwtSecurityTokenHandler _tokenHandler; private readonly IServiceProvider _serviceProvider; public MyJwtSecurityTokenHandler(IServiceProvider serviceProvider) { _tokenHandler = new JwtSecurityTokenHandler(); _serviceProvider = serviceProvider; } public int MaximumTokenSizeInBytes { get => _maxTokenSizeInBytes; set => _maxTokenSizeInBytes = value; } // 修正显式接口实现,返回true表示支持Token验证 bool ISecurityTokenValidator.CanValidateToken => true; public bool CanReadToken(string securityToken) { return _tokenHandler.CanReadToken(securityToken); } public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { try { // 创建作用域获取业务服务 using var scope = _serviceProvider.CreateScope(); var authService = scope.ServiceProvider.GetRequiredService<IAuthService>(); // 执行自定义验证逻辑 var username = authService.GetUsername(securityToken); if (string.IsNullOrEmpty(username)) { throw new SecurityTokenValidationException("Token验证失败:无法获取有效用户名"); } // 调用默认JWT验证逻辑完成基础验证 return _tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken); } catch (SecurityTokenValidationException) { // 直接抛出框架兼容的验证异常,交由认证中间件处理失败响应 throw; } catch (Exception ex) { validatedToken = null; throw new SecurityTokenValidationException("Token验证出错", ex); } } }
2. 注册自定义验证器到依赖注入容器
在Program.cs中,将自定义验证器注册为单例服务(符合JWT处理器的无状态生命周期特性):
// 注册自定义JWT验证器 builder.Services.AddSingleton<MyJwtSecurityTokenHandler>(); // 可选:同时注册为ISecurityTokenValidator接口,便于后续其他场景复用 builder.Services.AddSingleton<ISecurityTokenValidator>(sp => sp.GetRequiredService<MyJwtSecurityTokenHandler>());
3. 配置JWT Bearer时注入自定义验证器
使用PostConfigure延迟配置JWT选项(确保服务容器已完全构建,能正确解析依赖),替换默认Token验证器:
builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.RequireHttpsMetadata = true; options.SaveToken = true; options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("custom validation key")), ValidateIssuer = false, ValidateAudience = true, }; }); // 延迟注入自定义验证器,避免容器未构建完成导致的依赖解析失败 builder.Services.PostConfigure<JwtBearerOptions>((serviceProvider, options) => { var myTokenValidator = serviceProvider.GetRequiredService<MyJwtSecurityTokenHandler>(); options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Add(myTokenValidator); });
核心说明
- 选择
PostConfigure:在ConfigureServices阶段服务容器尚未完全初始化,直接获取服务可能失败;PostConfigure会在容器构建完成后执行,确保依赖解析正常。 - 单例生命周期:JWT处理器无状态,单例模式更符合性能要求。
- 抛出标准异常:用
SecurityTokenValidationException替代返回null,让ASP.NET Core认证中间件自动返回401/403标准响应。
内容的提问来源于stack exchange,提问作者B.Balamanigandan
相关产品推荐
相关产品推荐

