zoukankan      html  css  js  c++  java
  • Identity Server 4返回自定义用户Claim

    Identity Server 4返回自定义用户Claim

    Identity Server系列目录

    1. Blazor Server访问Identity Server 4单点登录 - SunnyTrudeau - 博客园 (cnblogs.com)
    2. Blazor Server访问Identity Server 4单点登录2-集成Asp.Net角色 - SunnyTrudeau - 博客园 (cnblogs.com)
    3. Blazor Server访问Identity Server 4-手机验证码登录 - SunnyTrudeau - 博客园 (cnblogs.com)
    4. Blazor MAUI客户端访问Identity Server登录 - SunnyTrudeau - 博客园 (cnblogs.com)
    5. Identity Server 4项目集成Blazor组件 - SunnyTrudeau - 博客园 (cnblogs.com)
    6. Identity Server 4退出登录自动跳转返回 - SunnyTrudeau - 博客园 (cnblogs.com)
    7. Identity Server通过ProfileService返回用户角色 - SunnyTrudeau - 博客园 (cnblogs.com)

    上一篇提到,尝试通过ProfileService返回更多用户声明,有的可以,有的不行。这个问题其实可以通过认证服务器的ProfileService 和客户端项目AddOpenIdConnectoptions.ClaimActions.MapJsonKey配置解决。官网有提到ClaimActions.MapJsonKey

    ASP.NET Core 中保存外部提供程序的其他声明和令牌 | Microsoft Docs

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");

    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");

    修改Identity Server 4认证服务器项目

    打开AspNetId4Web认证服务器项目,先升级用户实体类,增加一个字段:民族。

    public class ApplicationUser : IdentityUser

        {

            /// <summary>

            /// 民族

            /// </summary>

            public string Nation { get; set; }

        }

    生成一个数据库的迁移,打开程序包管理器控制台:

    PM> Add-Migration nation

    PM> Update-Database

    在种子数据初始化时给alicebob增加民族。

                            alice.Nation = "汉族";

                            bob.Nation = "壮族";

    在ProfileService中,把民族添加到用户claims,注意,要从数据库中查询用户,获取Nation字段,context.Subject里边是没有的。

    public class ProfileService : IProfileService
        {
            private readonly IServiceProvider _serviceProvider;
    
            public ProfileService(IServiceProvider serviceProvider)
            {
                _serviceProvider = serviceProvider;
            }
    
            public async Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                using var scope = _serviceProvider.CreateScope();
                var userMgr = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
                //按Name找不到
                //var user = await userMgr.FindByNameAsync(context.Subject.Identity.Name);
                //按Sub找得到
                string userId = context.Subject.FindFirstValue(JwtClaimTypes.Subject);
                var user = await userMgr.FindByIdAsync(userId);
    
                var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
                context.IssuedClaims.AddRange(nameClaim);
    
                var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
                context.IssuedClaims.AddRange(roleClaims);
    
                var emailClaims = context.Subject.FindAll(JwtClaimTypes.Email);
                context.IssuedClaims.AddRange(emailClaims);
    
                var phoneNumberClaims = context.Subject.FindAll(JwtClaimTypes.PhoneNumber);
                context.IssuedClaims.AddRange(phoneNumberClaims);
    
                //获取民族字段
                var nationClaim = new Claim("nation", user.Nation);
                context.IssuedClaims.Add(nationClaim);
    
                await Task.CompletedTask;
            }
    
            public async Task IsActiveAsync(IsActiveContext context)
            {
                await Task.CompletedTask;
            }

    修改Blazor Server客户端项目

    BlzOidc项目中,配置oidc参数时,添加映射的字段nation,上一篇测试发现PhoneNumber字段无法返回,添加映射也可以解决。

    //添加认证相关的服务
        private static void ConfigureAuthServices(IServiceCollection services)
        {
            //清除微软定义的clamis
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    
            //默认采用cookie认证方案,添加oidc认证方案
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "cookies";
                options.DefaultChallengeScheme = "oidc";
            })
                //配置cookie认证
                .AddCookie("cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    //id4服务的地址
                    options.Authority = "https://localhost:5001";
    
                    //id4配置的ClientId以及ClientSecrets
                    options.ClientId = "BlazorServerOidc";
                    options.ClientSecret = "BlazorServerOidc.Secret";
    
                    //认证模式
                    options.ResponseType = "code";
    
                    //保存token到本地
                    options.SaveTokens = true;
    
                    //很重要,指定从Identity Server的UserInfo地址来取Claim
                    //效果等同id4配置AlwaysIncludeUserClaimsInIdToken = true
                    options.GetClaimsFromUserInfoEndpoint = true;
    
                    //指定要取哪些资料(除Profile之外,Profile是默认包含的)
                    options.Scope.Add("scope1");
                    //通过ProfileService返回用户角色
                    //options.Scope.Add("role");
    
                    //映射自定义用户声明
                    options.ClaimActions.MapJsonKey(JwtClaimTypes.PhoneNumber, JwtClaimTypes.PhoneNumber);
                    options.ClaimActions.MapJsonKey("nation", "nation");
    
                    //这里是个ClaimType的转换,Identity Server的ClaimType和Blazor中间件使用的名称有区别,需要统一。
                    //User.Identity.Name=JwtClaimTypes.Name
                    options.TokenValidationParameters.NameClaimType = "name";
                    options.TokenValidationParameters.RoleClaimType = "role";
    
                    options.Events.OnUserInformationReceived = (context) =>
                    {
                        //id4返回的角色是字符串数组或者字符串,blazor server的角色是字符串,需要转换,不然无法获取到角色
                        ClaimsIdentity claimsId = context.Principal.Identity as ClaimsIdentity;
    
                        var roleElement = context.User.RootElement.GetProperty(JwtClaimTypes.Role);
                        if (roleElement.ValueKind == System.Text.Json.JsonValueKind.Array)
                        {
                            var roles = roleElement.EnumerateArray().Select(e => e.ToString());
                            claimsId.AddClaims(roles.Select(r => new Claim(JwtClaimTypes.Role, r)));
                        }
                        else
                        {
                            claimsId.AddClaim(new Claim(JwtClaimTypes.Role, roleElement.ToString()));
                        }
    
                        return Task.CompletedTask;
                    };
                });
    
        }

    VS2022调试运行AspNetId4Web认证服务器项目和BlzOidc项目,在BlzOidc主页点击登录,跳转到AspNetId4Web认证服务器,输入手机验证码登录,跳转回到BlzOidc主页,可以看到,想要的用户信息都有了

     

    DEMO代码地址:https://gitee.com/woodsun/blzid4

  • 相关阅读:
    Dynamically allocated memory 动态分配内存【malloc】Memory leaks 内存泄漏
    const pointers
    heap是堆,stack是栈
    Java中使用Cookie
    Postman注册、登录、导出、导入
    HttpServletRequest get post 入参
    判断设置的时间是否大于当前时间
    JS回车登录
    一个普通的Ajax
    Java工具类
  • 原文地址:https://www.cnblogs.com/sunnytrudeau/p/15631169.html
Copyright © 2011-2022 走看看