如何从 ISecurityTokenValidator 正确获取依赖范围的服务
Posted
技术标签:
【中文标题】如何从 ISecurityTokenValidator 正确获取依赖范围的服务【英文标题】:How to correctly get dependent scoped services from ISecurityTokenValidator 【发布时间】:2018-04-18 17:28:58 【问题描述】:在我的 asp.net core 2.0 Web 应用程序中,我有一个自定义的 ISecurityTokenValidator
来验证令牌。
它依赖于存储库来进行数据库查找 - 存储库本身被设置为范围依赖:
services.AddScoped<IMyRepository>(MyRepository);
现在因为 ISecurityTokenValidator 的设置方式而出现了奇怪的问题。
添加在ConfigureServices
:
.AddJwtBearer(options =>
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
)
看起来是这样的:
public class MyTokenValidator : ISecurityTokenValidator
private readonly IServiceProvider _serviceProvider;
public MyTokenValidator(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
public bool CanReadToken(string securityToken) => true;
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
var serviceScopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
var myRepository = scope.ServiceProvider.GetService<IMyRepository>();
var principalFactory = scope.ServiceProvider.GetService<IUserClaimsPrincipalFactory<User>>();
// Use the repo....
现在,因为 IsecurityTokenProvider
只被实例化一次,它实际上是一个单例。当我使用服务提供商请求IMyRepository
时,我发现我总是收到相同的对象 - 就它而言,没有新的范围,因为它在单例类中。
为了解决这个问题,您将在上面的代码中看到,每次调用令牌验证器时,我都必须手动强制一个新范围。这真的是解决这个问题的唯一方法吗,看来我正在努力让它在这里工作......
【问题讨论】:
我遇到了完全相同的问题,试图在令牌验证器中检索UserManager
。
我最终重构了这一切——我不需要挂起 jwt Auth,所以我创建了自己的“API 密钥”Auth 中间件
你的意思是你不需要挂起 jwt Auth?就我而言,我正在尝试使用 Google OAuth 从客户端发布的 JWT 令牌进行授权。所以看来我需要连接我自己的 Google JWT 令牌验证器类,它继承自 ISecurityTokenValidator
并实现 ValidateToken
,然后我可以将所有令牌验证委托给 google 提供的类中的方法:Google.Apis.Auth.GoogleJsonWebSignature.ValidateAsync
我使用的是.AddJwtToken
,但我使用的是我自己的 ISecurityTokenValidator,它实际上不需要对 JWT 令牌做任何事情。所以我把它全部撕掉,并用我自己的AuthenticationHandler
替换(可能不适用于你的场景)
啊,我明白了。如果您有兴趣,我在这里解释了我的需求和方法:***.com/questions/48727900/…
【参考方案1】:
老问题,但我发现解决此问题的最佳方法是使用 IPostConfigureOptions<JwtBearerOptions>
配置 SecurityTokenValidators。
首先注册 JWT 承载和选项
services.AddAuthentication(options =>
...
).AddJwtBearer(AuthenticateScheme, options =>
options.TokenValidationParameters = new TokenValidationParameters
...
;
);
然后注册IPostConfigureOptions<JwtBearerOptions>
的自定义实现
services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();
并注册ISecurityTokenValidator
的自定义实现
services.AddSingleton<MyCustomSecurityTokenValidator>();
CustomJwtBearerOptionsPostConfigureOptions 可能类似于:
public class CustomJwtBearerOptionsPostConfigureOptions : IPostConfigureOptions<JwtBearerOptions>
private readonly MyCustomSecurityTokenValidator _tokenValidator; //example dependancy
public CustomJwtBearerOptionsPostConfigureOptions(MyCustomSecurityTokenValidator tokenValidator)
_tokenValidator = tokenValidator;
public void PostConfigure(string name, JwtBearerOptions options)
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(_tokenValidator);
现在 options.SecurityTokenValidators 由 CustomJwtBearerOptionsPostConfigureOptions
配置,它通过依赖注入实例化并可以传递相关的规范。
【讨论】:
这是迄今为止我发现的唯一解决这个问题的方法,而且很简洁。希望它在 SO 中有更多的知名度。谢谢。 在尝试了很多不同的死胡同之后,这最终成为了唯一一个真正运作良好的东西,而无需进行深层次的定制。确认在 .net5.0 中工作 我从来不知道IPostConfigureOptions
!工作得很好:)以上是关于如何从 ISecurityTokenValidator 正确获取依赖范围的服务的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从回收器适配器发送到片段 |如何从 recyclerview 适配器调用片段函数
如何从服务器获取和设置 android 中的 API(从服务器获取 int 值)?如何绑定和实现这个