本文介绍了在dotnetcore 2.0中的“使用"中的用户界面中似乎未对用户进行身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to provide an ActiveUser property to Serilog.
Unfortunately I cannot seem to find the correct spot to check for the current user.

在下面的代码中,httpContext.User.Identity.IsAuthenticated始终为 false?

In the below code httpContext.User.Identity.IsAuthenticated is always false?

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

  • 承载令牌登录在用户正在使用的范围内正常工作经过验证的控制器方法,用户需要属于正确角色才能进行身份验证.尽管用户名设置不正确-存在声明,并且IsAuthenticated设置为true.
  • 如果我使用cookie登录,则正确设置了用户,并且正确设置了声明,并且Serilog正常工作.无论使用承载令牌还是cookie进行调用都是如此.一旦用户使用cookie登录,它便始终可以正常工作.
  • The bearer token login is working correctly insofar as the user isauthenticated to the controller methods, and the user needs to belongto the correct roles in order to be authenticated. Though the user name is not correctly set - the claims are present, and IsAuthenticated is set to true.
  • If I use the cookie login, the user is set correctly, and the claims are set correctly, and the Serilog works correctly. This is true whether using the bearer token or a cookie to call in. Once the user is logged in with a cookie it always works.

验证承载令牌后,是否立即设置了用户?

When the bearer token is validated, the user is not immediately set?

该项目是aspnetcore 2.0

The project is 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?}");
        });

在我的控制器方法中,正确设置了用户并进行了验证.

In my controller method, the User is set correctly, and is authenticated.

[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令牌已通过验证.中间件需要在令牌验证后执行.

edit
Digging into the problem further it would appear that the JWTBearer token is validated AFTER my middleware has already executed. The middleware needs to execute AFTER the token is validated.

TL; DR
(完整配置)

TL;DR
(the full configuration)

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

推荐答案

在使用如下所示的主体设置登录时,我已经复制了此问题:

I have replicated this issue when logging in using a principal set up as follows:

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

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

Then I login with SignInAsync. This too leads to User.Identity.Name having a value but the User.Identity.IsAuthenticated not being set to true.

现在,当我将authenticationType参数添加到ClaimsIdentity时,如下所示:

Now when I add the authenticationType parameter to ClaimsIdentity like this:

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

IsAuthenticated现在设置为true.

The IsAuthenticated is now set to true.

我不完全确定您的登录方式将如何工作,您可以在某处提到此authenticationType,也可以在创建JWT时将其传递出去.我就是这样做的.

I am not entirely sure how your sign in would work and you could mention this authenticationType somewhere or you could pass it along while creating the JWT. That is the way I had done it.

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

Update ok just noticed your comment about the Name not shown either, but you can still try setting the authenticationType. Also as far as your claims are right, you should be able to extract the principle using AuthenticateAsync. Once you can access the principle from the Context.User object, you can always customize the an authentication scheme to force in the principal.

更新2 对于您的情况,请在您的AddJwtBearer内部,尝试包括以下内容:

Update 2 In your case, inside your AddJwtBearer, try including this:

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

这篇关于在dotnetcore 2.0中的“使用"中的用户界面中似乎未对用户进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-16 13:13