c# - 用户似乎没有在 dotnet core 2.0 中的“Use”管道中进行身份验证

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

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

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

但仅当使用不记名 token 登录时

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

当不记名 token 被验证时,用户是不是立即设置?

项目是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?}");
        });

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

[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 token 。中间件需要在验证 token 后执行。

长话短说
(完整配置)

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

最佳答案

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

Since you have multiple authentication schemes registered and none is the default, authentication does not happen automatically as the request goes through the pipeline. That's why the HttpContext.User was empty/unauthenticated when it went through your custom middleware. In this "passive" mode, the authentication scheme won't be invoked until it is requested. In your example, this happens when the request passes through your AuthorizeFilter. This triggers the JWT authentication handler, which validates the token, authenticates and sets the Identity, etc. That's why the User is populated correctly by the time it gets to your controller action.

关于c# - 用户似乎没有在 dotnet core 2.0 中的“Use”管道中进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46274422/

相关文章:

c# - 您能否将 XAML 绘图图像转换回 SVG 以进行编辑?

c# - 如何使用 ajax 调用将 formcollection 传递给一个 Action ?

c# - 堆栈不足,无法继续安全地执行程序。 ASP.NET MVC 4

asp.net - 运行 IdentityServer4 的问题

IdentityServer4 - API Server如何与Identity Server通信

asp.net-mvc - 在我们使用 JWT token 的情况下,Asp.net 核心中的 session 和应用程序变量(因此没有基于 cookie 的 session )

c# - 配置 ASP.NET_SessionId cookie 过期

c# - 如何在 Windows Installer 自定义对话框中将字段设置为必填

c# - 具有运行时映射配置的自动映射器

asp.net - currentUser 作为模型绑定(bind)参数