Identity Server 4:ProfileService修改的Claim未在认证Cookie生效及name claim异常问题
问题解答
一、为什么默认情况下name Claim的值是邮箱?
这个情况通常和ASP.NET Identity以及IdentityServer4的默认行为直接相关:
ASP.NET Identity的用户属性映射:
很多项目的注册流程会直接用邮箱作为用户的UserName(毕竟邮箱是天然的唯一标识)。IdentityServer4的默认DefaultProfileService在生成nameClaim时,会先从用户的Claims集合里找ClaimTypes.Name,如果找不到,就直接取用户实体的UserName属性值。如果你的UserName就是邮箱,那nameClaim自然就显示为邮箱了。自定义Claim转换配置:
如果项目里自定义了ClaimsPrincipalFactory,或者在配置Identity时把EmailClaim映射到了Name类型,也会出现这种情况。比如类似这样的代码:services.AddIdentity<IdentityUser, IdentityRole>() .AddClaimsPrincipalFactory<CustomClaimsPrincipalFactory>();要是自定义的
CustomClaimsPrincipalFactory里把用户的Email赋值给了ClaimTypes.Name,那nameClaim就会变成邮箱。
二、为什么自定义ProfileService修改了name Claim,但IS4应用自己的认证Cookie里还是邮箱?
这里要搞清楚两个完全独立的Claims生成逻辑:
- SPA收到的Claims:这部分是由IdentityServer4的
ProfileService控制的,它负责生成ID Token和Access Token里的Claims,所以你修改ProfileService后,SPA里能看到更新后的nameClaim是正常的。 - IdentityServer4自身的认证Cookie:这个Cookie是ASP.NET Identity负责生成和管理的,它的Claims来自用户登录时ASP.NET Identity的
ClaimsPrincipalFactory,和IdentityServer的ProfileService没有任何关系。
要修改IS4自己Cookie里的name Claim,你需要自定义ASP.NET Identity的ClaimsPrincipalFactory:
比如创建一个自定义工厂类:
public class CustomClaimsPrincipalFactory : UserClaimsPrincipalFactory<IdentityUser> { public CustomClaimsPrincipalFactory(UserManager<IdentityUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor) { } protected override async Task<ClaimsIdentity> GenerateClaimsAsync(IdentityUser user) { var identity = await base.GenerateClaimsAsync(user); // 移除原有的name claim identity.RemoveClaim(identity.FindFirst(ClaimTypes.Name)); // 添加实际用户名作为name claim(这里替换成你存储实际用户名的字段) identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName)); return identity; } }
然后在Startup.cs里注册这个工厂:
services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders() .AddClaimsPrincipalFactory<CustomClaimsPrincipalFactory>();
这样用户登录时,ASP.NET Identity生成的认证Cookie里,name Claim就会是你设置的实际用户名了。
内容的提问来源于stack exchange,提问作者Miguel Moura
相关产品推荐
相关产品推荐

