ASP.NET Core注册JwtAuthenticationManager时如何传入DatabaseContext参数
解决方案
你可以通过服务工厂重载的方式实现依赖注入,无需手动实例化DatabaseContext,具体实现分为两种场景:
场景1:允许将IJwtAuthenticationManager的生命周期调整为Scoped(推荐)
默认DatabaseContext的注册生命周期为Scoped,和请求生命周期一致,将认证服务也调整为Scoped可以避免生命周期不匹配的问题,注册代码如下:
var key = "This is my auth key"; // 用工厂方法从容器中获取已注册的DatabaseContext services.AddScoped<IJwtAuthenticationManager>(sp => new JwtAuthenticationManager(sp.GetRequiredService<DatabaseContext>(), key) );
场景2:必须将IJwtAuthenticationManager注册为Singleton
如果必须使用单例生命周期,不能直接注入Scoped的DatabaseContext,否则会导致上下文在后续请求中被释放报错,需要修改JwtAuthenticationManager的实现,注入IServiceScopeFactory,每次调用Authenticate方法时主动创建作用域获取DatabaseContext:
第一步:修改JwtAuthenticationManager代码
private readonly string key; private readonly IServiceScopeFactory _scopeFactory; // 构造函数改为接收IServiceScopeFactory和密钥 public JwtAuthenticationManager(IServiceScopeFactory scopeFactory, string key) { _scopeFactory = scopeFactory; this.key = key; } public string Authenticate(string username, string password) { // 每次验证时创建独立作用域获取DatabaseContext using var scope = _scopeFactory.CreateScope(); var context = scope.ServiceProvider.GetRequiredService<DatabaseContext>(); var result = context.Credentials.FirstOrDefault(x => x.Username == username && x.Password == password); if (result == null) return null; var tokenHandler = new JwtSecurityTokenHandler(); var tokenKey = Encoding.ASCII.GetBytes(key); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, username) }), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(tokenKey), SecurityAlgorithms.HmacSha256Signature ) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); }
第二步:注册单例服务
var key = "This is my auth key"; services.AddSingleton<IJwtAuthenticationManager>(sp => new JwtAuthenticationManager(sp.GetRequiredService<IServiceScopeFactory>(), key) );
提示:你原有代码中的JwtAuthenticationManager类漏写了
private readonly DatabaseContext _context;字段定义,若选择场景1的方案记得先补全该字段。
内容的提问来源于stack exchange,提问作者Joel John Centeno
相关产品推荐
相关产品推荐

