【问题标题】:@context.user.identity.name is null when using .mapuniquejsonkey使用 .mapuniquejsonkey 时,@context.user.identity.name 为空
【发布时间】:2021-09-18 02:59:53
【问题描述】:

我有两个应用程序,Blazor 和 IdentityServer。我注意到在ConfigureServices method options.ClaimActions.MapUniqueJsonKey("role","role") 下的Startup.cs 文件和使用@context.user.identity.nameindex.razor 文件内部它返回null。但是当我评论 claimactions 时,将其替换为以下内容:

options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name"
                    };

                    options.UseTokenLifetime = false;

它将返回当前用户的电子邮件。 当我用上面的代码替换 claimactions.mapuniquejsonkey 行时它只返回一个值有什么原因吗?我试图理解为什么会这样。我在有关 TokenValidationParameters 的文档中看到了,但仍然没有像我想的那样理解它。

当我有 options.ClaimActions.MapUniqueJsonKey("role","role") 行时,它返回 null:

当我注释掉该行并将其替换为上面的这两行时:

如果您想查看完整代码,请参阅以下内容:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();


            services.AddSingleton(sp => new HttpClient { BaseAddress = new Uri("http://localhost:36626") }); // WebApi project

            services.AddTransient<IWeatherForecastServices, WeatherForecastServices>();

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)

                .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
                {
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.SignOutScheme = OpenIdConnectDefaults.AuthenticationScheme;

                    options.Authority = "https://localhost:5443"; // IdentityServer Project
                    options.ClientId = "interactive";
                    options.ClientSecret = "KEY";

                    options.ResponseType = "code";
                  
                    options.Scope.Add("profile"); // default scope
                    options.Scope.Add("scope2");
                    options.Scope.Add("roles");
                    options.Scope.Add("permissions");
                    options.Scope.Add("email");
                    options.ClaimActions.MapUniqueJsonKey("role", "role");

                  /*  options.TokenValidationParameters = new TokenValidationParameters
                      {
                         NameClaimType = "name"
                      };

                    options.UseTokenLifetime = false;  */

                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                   
                });

            services.AddScoped<TokenProvider>();

            services.AddCors(options =>
            {
                options.AddPolicy("Open", builder => builder.AllowAnyOrigin().AllowAnyHeader());
            }

            );
            
            services.AddAuthorization(options =>
            {
                options.AddPolicy(Policy.Policies.IsUser, 
              Policy.Policies.IsUserPolicy());
            });                     

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseCors("Open");

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }

Index.razor:

Index.razor

<AuthorizeView Policy="@Policy.Policies.IsUser">
    <h3>Welcome, <b>@context.User.Identity.Name</b></h3>
    <p>You can only see this if you satisfy the IsUser policy.</p>
</AuthorizeView>

来自 IdentityServer 的Config.cs

                .......
                new Client
                {
                    ClientId = "interactive",
                    ClientSecrets = { new Secret("KEY".Sha256()) },
                    RequirePkce = true,
                    AllowedGrantTypes = GrantTypes.Code,

                    RedirectUris = { "https://localhost:5445/signin-oidc", "https://localhost:44327/signin-oidc" },
                    FrontChannelLogoutUri = "https://localhost:5445/signout-oidc",
                    PostLogoutRedirectUris = { "https://localhost:5445/signout-callback-oidc" },
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AllowOfflineAccess = true,
                    AllowedScopes = { "openid", "profile", "email" , "scope2" ,"weatherforecast-api","roles","permissions"}
                },
            };

【问题讨论】:

    标签: c# asp.net-identity blazor identityserver4 blazor-server-side


    【解决方案1】:

    名称声明和角色声明映射到 ASP.NET Core HTTP 上下文中的默认属性。有时需要对默认属性使用不同的声明,或者名称声明和角色声明与默认值不匹配。声明可以使用 TokenValidationParameters 属性进行映射,并根据需要设置为任何声明。

    以下代码 sn -p 说明了 TokenValidationParameters 的使用:

      options.TokenValidationParameters = new TokenValidationParameters
       {
         NameClaimType = "email", 
         RoleClaimType = "role"
       };
    

    如您所见,名称声明映射到“电子邮件”字段,但通常它会映射到“姓名”字段。

    注意:由于您的设置请求配置文件范围 (options.Scope.Add("profile");),因此不需要额外的声明映射。也就是说NameClaimType = "name"是多余的。

    获取用户声明的另一种方法是使用 OpenID Connect 用户信息 API。 ASP.NET Core 客户端应用程序使用 GetClaimsFromUserInfoEndpoint 属性来配置它。与第一个设置的一个重要区别是,您必须使用 MapUniqueJsonKey 方法指定所需的声明,否则客户端应用程序中将只有 name、given_name 和 email 标准声明可用。 id_token 中包含的声明是默认映射的。这是与第一个选项的主要区别。您必须明确定义您需要的一些声明:

       // YOU MUST HAVE THE FIRST LINE WITHOUT WHICH YOU'LL GET NULL VALUES
       options.GetClaimsFromUserInfoEndpoint = true;
       options.ClaimActions.MapUniqueJsonKey("preferred_username", 
                                           "preferred_username");
       options.ClaimActions.MapUniqueJsonKey("gender", "gender");
       options.ClaimActions.MapUniqueJsonKey("role","role");
    

    注意:您应该从我和 Brian Parker 那里寻找与身份验证和授权相关的答案。我们已经回答了 WebAssembly 和 Blazor 服务器应用程序中的许多问题。这些不是关于该主题的文章,而是我们提供给开发人员的解决方案,它们涵盖了该主题的许多方面,包括自定义声明、声明转换等。Brian Parker 在 Github 中也有完整的应用程序...查看。

    【讨论】:

      猜你喜欢
      • 2018-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 2012-05-31
      相关资源
      最近更新 更多