如何从ISecurityTokenValidator正确获取依赖范围的服务

Mat*_*rts 6 asp.net-core

在我的asp.net core 2.0网络应用程序中,我有一个ISecurityTokenValidator用于验证令牌的自定义。

它依赖于存储库来执行db查找-存储库本身被设置为作用域依赖项:

services.AddScoped<IMyRepository>(MyRepository);
Run Code Online (Sandbox Code Playgroud)

现在,由于ISecurityTokenValidator的设置方式而变得有趣。

它添加在ConfigureServices

.AddJwtBearer(options =>
    {
        options.SecurityTokenValidators.Clear();
        options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
    })
Run Code Online (Sandbox Code Playgroud)

它是这样的:

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....

        }

    }
}
Run Code Online (Sandbox Code Playgroud)

现在,由于IsecurityTokenProvider仅实例化一次,因此实际上是单例。当我使用服务提供商提出要求时,IMyRepository我发现我总是收到相同的对象-就它而言,没有新的作用域,因为它在单例类中。

为了解决这个问题,您将在上面的代码中看到,每次调用令牌验证器时,Ive必须手动强制使用新作用域。这真的是解决此问题的唯一方法,似乎我正在四处寻找使其在这里工作...

her*_*ist 19

老问题,但我发现解决这个问题的最好方法是使用IPostConfigureOptions<JwtBearerOptions>配置 SecurityTokenValidators。

首先注册JWT承载和选项

        services.AddAuthentication(options =>
        {
            ...
        }).AddJwtBearer(AuthenticateScheme, options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ...
            };
        });
Run Code Online (Sandbox Code Playgroud)

然后注册一个自定义实现 IPostConfigureOptions<JwtBearerOptions>

    services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();
Run Code Online (Sandbox Code Playgroud)

并注册一个自定义实现 ISecurityTokenValidator

    services.AddSingleton<MyCustomSecurityTokenValidator>();
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在 options.SecurityTokenValidators 由CustomJwtBearerOptionsPostConfigureOptions它配置,通过依赖注入实例化并且可以传递相关的规范。