2017-10-18 85 views
1

我想在ASP.NET Core 2.0中正确使用DI以使我的自定义方法处理在验证期间验证JWT令牌后触发的OnTokenValidated事件。下面的解决方案的工作,,除了,在处理程序中,我使用注入服务,命中MemoryCache来检查控制器中其他位置添加的缓存项目(我已验证它们已添加并保留),以及何时访问缓存总是空的。我怀疑这是因为我的自定义处理程序对象是由不同的容器创建的(由于早期的BuildServiceProvider()调用?),并且正在使用单独的MemoryCache(或类似的)实例。问题处理OnTokenValidated在startup.cs中分配的委托

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

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

我的自定义处理程序类如下。该ValidateSessionAsync()调用使用注入AppSessionService访问的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."); 
    } 
} 

如果自定义OnTokenValidated方法包含简单的逻辑,并没有需要注入的服务,我会用一个匿名函数内联它或者在startup.cs中私下声明它。如果可以的话,我宁愿修复这种方法,但我会向其他人开放。

回答

1

而不是使用静态/单身事件,考虑继承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); 
      }); 
    } 
} 
+0

没错。这就是诀窍! – coryseaman