使用在startup.cs中分配的委托处理OnTokenValidated的问题

cor*_*man 2 c# dependency-injection asp.net-core

我想在ASP.NET Core 2.0中正确使用DI,以便让我的自定义方法处理OnTokenValidated在身份验证期间验证JWT令牌后触发的事件.下面的解决方案有效,除了在处理程序中我使用一个注入的服务MemoryCache来检查控制器中其他地方添加的缓存项(我已经验证它们已被添加和保留),并且当它被访问时,缓存总是空.我怀疑这是因为我的自定义处理程序对象是由另一个容器创建的(由于早期BuildServiceProvider()调用?)并且正在使用单独的MemoryCache(或类似的)实例.

如果是这种情况,我想我不清楚如何ConfigureServices()在startup.cs中正确添加和引用我的类和方法,以便它按预期工作.这就是我所拥有的:

public void ConfigureServices(IServiceCollection services)
    {
    services.AddMemoryCache();
    ...
    services.AddScoped<IJwtTokenValidatedHandler, JwtTokenValidatedHandler>();
    // add other services
    ...
    var sp = services.BuildServiceProvider();
    services.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, bOptions =>
        {
            // Configure JwtBearerOptions
            bOptions.Events = new JwtBearerEvents
            {
                OnTokenValidated = sp.GetService<JwtTokenValidatedHandler>().JwtTokenValidated
            };
        }
Run Code Online (Sandbox Code Playgroud)

我的自定义处理程序类如下.该ValidateSessionAsync()调用使用AppSessionServiceinject来访问MemoryCache对象并确保存在缓存条目:

public class JwtTokenValidatedHandler : IJwtTokenValidatedHandler
{
    AppSessionService _session;
    public JwtTokenValidatedHandler(AppSessionService session)
    {
        _session = session;
    }
    public async Task JwtTokenValidated(TokenValidatedContext context)
    {
        // Add the access_token as a claim, as we may actually need it
        var accessToken = context.SecurityToken as JwtSecurityToken;
        if (Guid.TryParse(accessToken.Id, out Guid sessionId))
        {
            if (await _session.ValidateSessionAsync(sessionId))
            {
                return;
            }
        }
        throw new SecurityTokenValidationException("Session not valid for provided token.");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果自定义OnTokenValidated方法包含简单逻辑并且不需要注入服务,我会使用匿名函数对其进行内联,或者在startup.cs中私下声明它.如果可以的话,我更愿意修复这种方法,但我会对其他人持开放态度.

Kév*_*let 7

而不是使用static/singleton事件,考虑子类化JwtBearerEvents并使用JwtBearerOptions.EventsType选项:

public class CustomJwtBearerEvents : JwtBearerEvents
{
    AppSessionService _session;
    public CustomJwtBearerEvents(AppSessionService session)
    {
        _session = session;
    }

    public override async Task TokenValidated(TokenValidatedContext context)
    {
        // Add the access_token as a claim, as we may actually need it
        var accessToken = context.SecurityToken as JwtSecurityToken;
        if (Guid.TryParse(accessToken.Id, out Guid sessionId))
        {
            if (await _session.ValidateSessionAsync(sessionId))
            {
                return;
            }
        }
        throw new SecurityTokenValidationException("Session not valid for provided token.");
    }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<CustomJwtBearerEvents>();

        services.AddAuthentication()
            .AddJwtBearer(options =>
            {
                options.EventsType = typeof(CustomJwtBearerEvents);
            });
    }
}
Run Code Online (Sandbox Code Playgroud)