【问题标题】:User doesn't seem authenticated in the pipline inside`Use` in dotnetcore 2.0用户似乎没有在 dotnet core 2.0 中的“Use”内的管道中经过身份验证
【发布时间】:2018-02-26 16:52:40
【问题描述】:

我正在尝试向 Serilog 提供 ActiveUser 属性。
不幸的是,我似乎找不到正确的位置来检查当前用户。

在下面的代码中httpContext.User.Identity.IsAuthenticated总是false?

但仅在使用不记名令牌登录时

  • 不记名令牌登录工作正常,只要用户是 验证到控制器方法,并且用户需要属于 到正确的角色以便进行身份验证。虽然用户名设置不正确 - 声明存在,并且 IsAuthenticated 设置为 true。
  • 如果我使用cookie登录,用户设置正确,声明设置正确,Serilog工作正常。无论是使用不记名令牌还是使用 cookie 来调用都是如此。一旦用户使用 cookie 登录,它就始终有效。

当承载令牌被验证时,用户不是立即设置的吗?

项目是aspnetcore 2.0

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

    ... (other configuration items)

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

    app.Use(async (httpContext, next) =>
    {
        // HERE IsAuthenticated IS ALWAYS FALSE
        // HERE THE CLAIMS ARE ALWAYS EMPTY, UNLESS
        // I LOGIN USING THE COOKIE AS WELL - THEN IT WORKS
        var userName = httpContext.User.Identity.IsAuthenticated 
            ? httpContext.User.GetClaim("name")
            : "(unknown)";
        LogContext.PushProperty(
            "ActiveUser",
            !string.IsNullOrWhiteSpace(userName)
                 ? userName
                 : "(unknown)");
        await next.Invoke();
    });

    app.UseMvc(
        routes =>
        {
            routes.MapRoute(
                "default",
                "{controller=Home}/{action=Index}/{id?}");
        });

在我的控制器方法中,用户设置正确,并且经过身份验证。

[Authorize]
[HttpGet("user")]
public object UserDetail()
{
    // HERE THE CLAIMS ARE SET, IsAuthenticated IS ALWAYS TRUE
    // AS THE USER MUST BE AUTHENTICATED TO GET HERE
    Debug.Assert(this.User.Identity.IsAuthenticated == true)

编辑
进一步深入研究这个问题,JWTBearer 令牌似乎是在我的中间件已经执行之后得到验证的。中间件需要在验证令牌后执行。

TL;DR
(完整配置)

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) =>
                    {
                        var userName = httpContext.User.Identity.IsAuthenticated 
                        ? httpContext.User.GetClaim("email")
                        : "(unknown)";
                        LogContext.PushProperty("ActiveUser", !string.IsNullOrWhiteSpace(userName) ? userName : "(unknown)");
                        await next.Invoke();
                    });

    app.UseMvc(
        routes =>
        {
            routes.MapRoute(
                "default",
                "{controller=Home}/{action=Index}/{id?}");
        });

}

(更多配置)

   public void ConfigureServices(IServiceCollection services)
   {
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        services.AddAuthentication()
            .AddOpenIdConnect(
                o =>
                {
                    o.Authority = "https://localhost:44319";
                    o.ClientId = "api";
                    o.ClientSecret = "secret";
                    o.RequireHttpsMetadata = false;
                    o.ResponseType = "code id_token token";
                    o.GetClaimsFromUserInfoEndpoint = true;
                })
            .AddJwtBearer(
                o =>
                {
                    o.Authority = "https://localhost:44319";
                    o.Audience = "api";
                    o.RequireHttpsMetadata = false;
                    //o.SaveToken = true;
                });

        services.AddMemoryCache();
        services.AddIdentity<ApplicationUser, ApplicationRole>(
                x =>
                {
                    x.Password.RequireNonAlphanumeric = false;
                    x.Password.RequireUppercase = false;
                })
            .AddEntityFrameworkStores<FormWorkxContext>()
            .AddDefaultTokenProviders()
            .AddIdentityServer();

        // NB
        services.Configure<IdentityOptions>(
            options =>
            {
                options.ClaimsIdentity.RoleClaimType = ClaimTypes.Role;
                options.ClaimsIdentity.UserNameClaimType = ClaimTypes.Name;
            });

        services.ConfigureApplicationCookie(
            options =>
            {
                options.LoginPath = "/login";
                options.LogoutPath = "/logout";
                options.Events.OnRedirectToLogin = this.ProcessStatusCodeResponse;
            });

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApis())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>();

        services.AddTransient<IEmailSender, EmailSender>();

        services.AddMvc(
                _ =>
                {
                    _.Filters.Add(
                        new AuthorizeFilter(
                            new AuthorizationPolicyBuilder(
                                    JwtBearerDefaults.AuthenticationScheme,
                                    IdentityConstants.ApplicationScheme)
                                .RequireAuthenticatedUser()
                                .Build()));
                    _.Filters.Add(new ExceptionFilter());
                    _.ModelBinderProviders.Insert(0, new PartyModelBinderProvider());
                    _.ModelBinderProviders.Insert(0, new DbGeographyModelBinder());
                    _.ModelMetadataDetailsProviders.Add(new KeyTypeModelMetadataProvider());
                })
            .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>())
            .AddJsonOptions(json => json.SerializerSettings.Converters.Add(new DbGeographyJsonConverter()));
    }

【问题讨论】:

  • 显示配置服务方法。
  • 当您说“用户设置正确”时,您的意思是 Identity.Name 对吗?如果是,我遇到了同样的问题,它向我显示了名称,但没有将 IsAuthenticated 设置为 true。当我更改我的登录代码时,它会将登录设置为 true。您究竟是如何登录用户的。
  • 您的 Configure 方法仅在应用启动时运行一次,此时没有用户甚至 http 上下文。我还没有使用 Serilog(还),但在实际记录某些内容时,您可能需要将用户作为数据的一部分。 LogContext 听起来它也是一个单例,与特定用户会话无关。
  • @Neville,抱歉,我应该具体一点,未设置任何声明,未设置用户。用户根本不存在。稍后在管道中(在实际的控制器方法中)它都设置正确。不幸的是,登录很复杂 - 使用 JWTToken 和身份服务器。我可以发布完整的配置 - 我只是想尽可能简短。
  • @rory_za,add 方法采用一个 lambda,该 lambda 在管道上为每个请求重新执行。所以是的,当第一次传入 lambda 时,没有上下文,但 lambda 接收当前上下文和序列中的下一个处理程序。

标签: c# asp.net-mvc identityserver4 serilog asp.net-core-middleware


【解决方案1】:

我在使用如下设置的主体登录时复制了这个问题:

var principal = new ClaimsPrincipal(new ClaimsIdentity(claims));

然后我使用SignInAsync 登录。这也导致User.Identity.Name 具有值但User.Identity.IsAuthenticated 未设置为true。

现在当我像这样将authenticationType 参数添加到ClaimsIdentity 时:

var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "local"));

IsAuthenticated 现在设置为 true。

我不完全确定您的登录将如何工作,您可以在某处提及此authenticationType,或者您可以在创建 JWT 时传递它。我就是这样做的。

更新好的,刚刚注意到您对名称的评论也没有显示,但您仍然可以尝试设置 authenticationType。此外,只要您的主张是正确的,您应该能够使用AuthenticateAsync 提取原理。一旦您可以从 Context.User 对象访问主体,您始终可以自定义身份验证方案以强制在主体中。

更新 2 在您的情况下,在您的 AddJwtBearer 中,尝试包含以下内容:

o.Events.OnTokenValidated = async (context) => {
    context.Principal = new ClaimsPrincipal(new ClaimsIdentity(context.Principal.Claims, "local"));
};

【讨论】:

  • 在验证令牌时未设置上下文用户中的 JWTBearer 身份验证似乎存在问题 - 我不确定在验证令牌时使用什么挂钩来更新原理。
  • 它是内置的身份验证方案吗?你能找到扩展它的方法吗?
  • 这是 dotnetcore 中内置的 AddJwtBearer。我想我会试着问另一个更简单的问题。这一条红鲱鱼太多了。
  • 是的,在 jwt 的构建中,我经常看到人们设置这样的事件
  • 事件被触发了,我想你已经接近了,它会解决我的问题,现在的问题是在验证令牌之前调用了该死的App.Use(...
【解决方案2】:

复制 my answer from your other related question 以防万一有人遇到此问题并想知道发生了什么:

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

【讨论】:

    【解决方案3】:

    通过添加以下代码行在您的自定义中间件中显式验证用户:

    var result = await context.Request.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);//AuthenticationOptions.DefaultAuthenticateScheme)
                if (result.Succeeded)
                {
                    //context.User.AddIdentity(result.Principal);
                    context.User = result.Principal;
                }
    

    【讨论】:

      猜你喜欢
      • 2018-02-04
      • 2018-05-28
      • 2018-04-05
      • 1970-01-01
      • 2018-01-24
      • 2018-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多