验证JWT令牌后访问dotnetcore中间件

时间:2017-09-19 09:12:48

标签: c# asp.net-mvc .net-core jwt

我正在使用JWT承载认证,配置如下。

  

我的问题是中间件在令牌验证之前正在执行   如何配置中间件以后运行?

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

2 个答案:

答案 0 :(得分:8)

看起来你已经找到了解决问题的好方法,但我想我会添加一个答案来解释你所看到的行为。

由于您注册了多个身份验证方案,并且没有一个是默认方案,因此当请求通过管道时,身份验证不会自动发生。这就是HttpContext.User在通过您的自定义中间件时为空/未经身份验证的原因。在这种“被动”模式中,在请求之前不会调用认证方案。在您的示例中,当请求通过您的AuthorizeFilter时会发生这种情况。这会触发JWT身份验证处理程序,该处理程序验证令牌,验证身份并设置身份等。这就是为什么(as in your other questionUser在到达控制器操作时正确填充的原因。

对于您的场景可能没有意义(因为您同时使用了cookie和jwt)...但是,如果您确实希望自动进行Jwt身份验证,请为其他中间件设置HttpContext.User在管道中,您只需要在配置身份验证时将其注册为默认方案:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

答案 1 :(得分:3)

基于@ 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());

        ...