使用 .mapuniquejsonkey 时,@context.user.identity.name 为空

Posted

技术标签:

【中文标题】使用 .mapuniquejsonkey 时,@context.user.identity.name 为空【英文标题】:@context.user.identity.name is null when using .mapuniquejsonkey 【发布时间】: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"
                ,
            ;

【问题讨论】:

【参考方案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 中也有完整的应用程序...查看。

【讨论】:

以上是关于使用 .mapuniquejsonkey 时,@context.user.identity.name 为空的主要内容,如果未能解决你的问题,请参考以下文章

我正在使用 Enterprise Architect,在 C/C++ 中进行逆向工程时遇到了一些问题

在编译时为大型 C/C++ 项目使用 GNU m4

为啥在使用 wprintf 时 ©(版权符号)被替换为 (C)?

使用 CMD /c 时如何绕过字符限制?

使用 C 扩展 python 时发现内存泄漏

移动窗口时 C++/WinApi 内存使用率上升