如何使用JWTService配置JwtBearer?规避不推荐的服务构建方式
问题:如何在AddJwtBearer中复用JWTService的TokenValidationParameters配置?
我正在应用中使用JwtBearer配置AuthenticationService,并将JWT配置抽象为JWTService以在全应用中复用,以下是我的代码:
builder.Services.AddSingleton<JWTService>(); builder.Services.AddAuthorization(options => { options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession")); }); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.TokenValidationParameters = ...; });
public class JWTService { private IConfiguration _configuration; public JWTService(IConfiguration configuration) { _configuration = configuration; } public TokenValidationParameters Config() { return new TokenValidationParameters() { ValidateActor = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ClockSkew = TimeSpan.Zero, ValidAudience = _configuration["JwtBearerTokenSettings:Audience"], ValidIssuer = _configuration["JwtBearerTokenSettings:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtBearerTokenSettings:SecretKey"])) }; } }
请问如何获取JWTService并将其Config方法的返回值作为AddJwtBearer的参数?我曾通过builder.Services.BuildServiceProvider().GetServices实现,但该方式不被推荐,是否有其他可行方案?
解决方案
方案1:使用AddJwtBearer的服务提供者重载
AddJwtBearer提供了接受IServiceProvider的重载,可以在配置阶段从已注册的服务容器中获取JWTService,这是官方推荐的方式,避免提前构建服务容器导致的问题:
builder.Services.AddSingleton<JWTService>(); builder.Services.AddAuthorization(options => { options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession")); }); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer((serviceProvider, options) => { // 从服务容器中获取已注册的JWTService实例 var jwtService = serviceProvider.GetRequiredService<JWTService>(); options.TokenValidationParameters = jwtService.Config(); });
这种方式不会创建额外的服务容器实例,避免了服务重复注册、状态不一致等问题,完全符合依赖注入的设计原则。
方案2:简化配置逻辑(无需依赖注入实例)
由于你的JWTService当前仅负责读取配置并返回TokenValidationParameters,没有其他业务逻辑或依赖,可以直接从IConfiguration构建参数,或者封装成静态工具类复用逻辑:
方式A:直接读取配置
var tokenValidationParams = new TokenValidationParameters() { ValidateActor = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ClockSkew = TimeSpan.Zero, ValidAudience = builder.Configuration["JwtBearerTokenSettings:Audience"], ValidIssuer = builder.Configuration["JwtBearerTokenSettings:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtBearerTokenSettings:SecretKey"])) }; builder.Services.AddAuthorization(options => { options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession")); }); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.TokenValidationParameters = tokenValidationParams; });
方式B:封装成静态工具类(复用逻辑)
public static class JwtConfigHelper { public static TokenValidationParameters GetTokenValidationParameters(IConfiguration configuration) { return new TokenValidationParameters() { ValidateActor = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ClockSkew = TimeSpan.Zero, ValidAudience = configuration["JwtBearerTokenSettings:Audience"], ValidIssuer = configuration["JwtBearerTokenSettings:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtBearerTokenSettings:SecretKey"])) }; } }
然后在配置时调用:
var tokenValidationParams = JwtConfigHelper.GetTokenValidationParameters(builder.Configuration); builder.Services.AddAuthorization(options => { options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession")); }); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.TokenValidationParameters = tokenValidationParams; });
这种方式更轻量,不需要依赖注入容器,适合仅封装配置读取的场景。
内容的提问来源于stack exchange,提问作者Lucas Bustos
相关产品推荐
相关产品推荐

