用户似乎没有在dotnetcore 2.0

时间:2017-09-18 08:05:43

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

我正在尝试向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()));
    }

3 个答案:

答案 0 :(得分:2)

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

  

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

通过添加以下代码行,在自定义中间件中对用户进行显式身份验证:

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