如何从 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&lt;JwtBearerOptions&gt; 配置 SecurityTokenValidators。

首先注册 JWT 承载和选项

        services.AddAuthentication(options =>
        
            ...
        ).AddJwtBearer(AuthenticateScheme, options =>
        
            options.TokenValidationParameters = new TokenValidationParameters
            
                ...
            ;
        );

然后注册IPostConfigureOptions&lt;JwtBearerOptions&gt;的自定义实现

    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 适配器调用片段函数

如何从 Firebase 获取所有设备令牌?

如何直接从类调用从接口继承的方法?

如何从服务器获取和设置 android 中的 API(从服务器获取 int 值)?如何绑定和实现这个

如何从Mac从android studio中的fabric注销? [复制]

如何从设备中获取 PDF 文件以便能够从我的应用程序中上传?