Identity Server 4返回自定义用户Claim
2021/12/3 23:21:34
本文主要是介绍Identity Server 4返回自定义用户Claim,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Identity Server 4返回自定义用户Claim
Identity Server系列目录
- Blazor Server访问Identity Server 4单点登录 - SunnyTrudeau - 博客园 (cnblogs.com)
- Blazor Server访问Identity Server 4单点登录2-集成Asp.Net角色 - SunnyTrudeau - 博客园 (cnblogs.com)
- Blazor Server访问Identity Server 4-手机验证码登录 - SunnyTrudeau - 博客园 (cnblogs.com)
- Blazor MAUI客户端访问Identity Server登录 - SunnyTrudeau - 博客园 (cnblogs.com)
- 在Identity Server 4项目集成Blazor组件 - SunnyTrudeau - 博客园 (cnblogs.com)
- Identity Server 4退出登录自动跳转返回 - SunnyTrudeau - 博客园 (cnblogs.com)
- Identity Server通过ProfileService返回用户角色 - SunnyTrudeau - 博客园 (cnblogs.com)
上一篇提到,尝试通过ProfileService返回更多用户声明,有的可以,有的不行。这个问题其实可以通过认证服务器的ProfileService 和客户端项目AddOpenIdConnect的options.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
在种子数据初始化时给alice和bob增加民族。
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
这篇关于Identity Server 4返回自定义用户Claim的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26MATLAB 中 A(7)=[];什么意思?-icode9专业技术文章分享
- 2024-11-26UniApp 中如何实现使用输入法时保持页面列表不动的效果?-icode9专业技术文章分享
- 2024-11-26在 UniApp 中怎么实现输入法弹出时禁止页面向上滚动?-icode9专业技术文章分享
- 2024-11-26WebSocket是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-26页面有多个ref 要动态传入怎么实现?-icode9专业技术文章分享
- 2024-11-26在 UniApp 中实现一个底部输入框的常见方法有哪些?-icode9专业技术文章分享
- 2024-11-26RocketMQ入门指南:搭建与使用全流程详解
- 2024-11-26RocketMQ入门教程:轻松搭建与使用指南
- 2024-11-26手写RocketMQ:从入门到实践的简单教程
- 2024-11-25【机器学习(二)】分类和回归任务-决策树(Decision Tree,DT)算法-Sentosa_DSML社区版