2017-09-19 41 views
4

我正在使用JWT承載驗證,配置如下。在驗證JWT令牌之後訪問dotnetcore中間件

我的問題是中間件在驗證令牌之前執行。
如何配置中間件以後運行?

services.AddAuthentication() 
    .AddCookie(_ => _.SlidingExpiration = true) 
    .AddJwtBearer(
     _ => 
     { 
      _.Events = new JwtBearerEvents 
      { 
       // THIS CODE EXECUTES AFTER THE MIDDLEWARE???? 
       OnTokenValidated = context => 
       { 
        context.Principal = new ClaimsPrincipal(
         new ClaimsIdentity(context.Principal.Claims, "local")); 
        return Task.CompletedTask; 
       } 
      }; 
      _.RequireHttpsMetadata = false; 
      _.SaveToken = false; 
      _.TokenValidationParameters = new TokenValidationParameters() 
      { 
       ValidIssuer = this.Configuration["Tokens:Issuer"], 
       ValidAudience = this.Configuration["Tokens:Issuer"], 
       IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.Configuration["Tokens:Key"])), 
      }; 
     }); 

我試圖添加到中間件訪問當前用戶的管道。此代碼不幸執行之前令牌驗證。之後如何讓它執行?

public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
{ 
    if (env.IsDevelopment()) 
    { 
     app.UseDeveloperExceptionPage(); 
     app.UseBrowserLink(); 
    } 
    else 
    { 
     app.UseExceptionHandler("/Home/Error"); 
    } 

    app.UseStaticFiles(); 
    app.UseIdentityServer(); 
    app.UseAuthentication(); 

    app.Use(async (httpContext, next) => 
     { 
      // THIS CODE EXECUTES BEFORE THE TOKEN IS VALIDATED IN OnTokenValidated. 
      var userName = httpContext.User.Identity.IsAuthenticated 
      ? httpContext.User.GetClaim("email") 
      : "(unknown)"; 
      LogContext.PushProperty("ActiveUser", !string.IsNullOrWhiteSpace(userName) ? userName : "(unknown)"); 
      await next.Invoke(); 
     }); 
+0

也許過濾器是一種更好的方法。 – leppie

+0

能否詳細說明一下?顯然,我需要訪問上下文嗎? – Jim

+0

https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters(或者,也許你可以從那裏感受一個更好的主意) – leppie

回答

4

看起來你已經找到了一個很好的解決你的問題,但我想我會添加一個答案來解釋你所看到的行爲。

由於您有多個身份驗證方案註冊,並且沒有默認身份驗證,所以身份驗證不會在請求通過管道時自動發生。這就是爲什麼HttpContext.User在通過自定義中間件時爲空/未經認證的原因。在這種「被動」模式下,認證方案在請求之前不會被調用。在你的例子中,當請求通過AuthorizeFilter時發生這種情況。這會觸發JWT身份驗證處理程序,它會驗證令牌,驗證身份並設置身份等。這就是爲什麼(as in your other questionUser在獲取到控制器操作時正確填充的原因。

這對您的場景可能沒有意義(因爲您同時使用了cookie和jwt)......但是,如果您確實希望Jwt身份驗證自動發生,請爲管道中的其他中間件設置HttpContext.User,您只需要在配置身份驗證時將其註冊爲默認方案:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) 
+2

我可能會在某個時候刪除cookie,但希望兩者都能正常工作。我沒有預見到這些棘手的情況。雖然我的解決方案有效 - 我接受你的答案 - 這是一個很好的解釋,它肯定會幫助其他工程師解決持證人問題。 – Jim

2

根據@ leppie的評論,這裏是一個可行的解決方案。

public class ActiveUserFilter : IAsyncActionFilter 
{ 
    public async Task OnActionExecutionAsync(
     ActionExecutingContext context, 
     ActionExecutionDelegate next) 
    { 
     var userName = context.HttpContext.User.Identity.IsAuthenticated 
     ? context.HttpContext.User.GetClaim("email") 
     : "(unknown)"; 
     using (LogContext.PushProperty("ActiveUser", !string.IsNullOrWhiteSpace(userName) ? userName : "(unknown)")) 
      await next(); 
    } 
} 

插入如下...

services.AddMvc(
    _ => 
    { 
     _.Filters.Add(
      new AuthorizeFilter(
       new AuthorizationPolicyBuilder(
       JwtBearerDefaults.AuthenticationScheme, 
       IdentityConstants.ApplicationScheme) 
       .RequireAuthenticatedUser() 
       .Build())); 
     _.Filters.Add(new ActiveUserFilter()); 

     ...