Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
938 views
in Technique[技术] by (71.8m points)

asp.net core - How to correctly get dependent scoped services from ISecurityTokenValidator

In my asp.net core 2.0 web app, I've got a custom ISecurityTokenValidator which validates tokens.

It depends on a repository to do a db lookup - the repository itself is setup as a scoped dependency:

services.AddScoped<IMyRepository>(MyRepository);

Now the funkiness comes about because of the way the ISecurityTokenValidator is setup.

It's added in ConfigureServices:

.AddJwtBearer(options =>
    {
        options.SecurityTokenValidators.Clear();
        options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
    })

This is how it looks:

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

        }

    }
}

Now, because the IsecurityTokenProvider is only instantiated once, it's effectively a singleton. When I use the service provider to ask for a IMyRepository I was finding that I was always received the same object - there is no new scope as far as it was concerned, because it's in a singleton class.

To get round that, you'll see in the code above Ive had to manually force a new scope every time the token validator is called. Is this really the only way to resolve this, it seems like I'm hacking around to make it work here...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Old question but the best way I have found to solve this problem is to use IPostConfigureOptions<JwtBearerOptions> to configure SecurityTokenValidators.

First register the JWT bearer and options

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

Then register a custom implementation of IPostConfigureOptions<JwtBearerOptions>

    services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();

And register a custom implementation of ISecurityTokenValidator

    services.AddSingleton<MyCustomSecurityTokenValidator>();

CustomJwtBearerOptionsPostConfigureOptions could look something like:

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);
    }
}

Now options.SecurityTokenValidators is configured by CustomJwtBearerOptionsPostConfigureOptions which is instantiated by dependency injection and can pass on the relevant decencies.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...