DefaultInboundClaimTypeMap.Clear()
在 AspNet Core 中使用 AspNetCoreIdentity 常常伴随着这么一条语句
public void ConfigureServices(IServiceCollection services) {
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}
这次正好遇到了一个问题代码
var user = await _userManager.GetUserAsync(HttpContext.User);
IdentityServer4(简称ids4) 与 AspNetCoreIdentity 部署在同一个项目中
由 ids4 生成的 jwt 包含 sub 为 1 的 claim ,HttpContext.User 也包含 jwt 中的 claims,所以理应代码中的 user 变量不为 null,但实际为 null。先看看源码
GetUserAsync 源码:
public virtual Task<TUser> GetUserAsync(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException("principal");
}
string userId = GetUserId(principal);
if (userId != null)
{
return FindByIdAsync(userId);
}
return Task.FromResult<TUser>(null);
}
GetUserId 源码:
public virtual string GetUserId(ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException("principal");
}
return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}
ClaimsIdentity.UserIdClaimType 值:
对我的应用代码 User.Claims 调试,发现 jwt 中的 sub 修改为了 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
,所以理应是能找到用户信息的。
我怀疑 UserIdClaimType 的值并不是 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
,我的代码中并没有对 ClaimsIdentity 进行重新赋值,只能调试 dll 文件了。
使用 VS 的插件 reflector(收费)为程序集 Microsoft.Extensions.Identity.Core 生成 pdb 文件进行调试,如我所想 UserIdClaimType 的值是 sub。
原因是 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap
进行了映射,所以解决 user 为 null 有两种方法:
- JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear() 清除映射
- 在服务注入中对 ClaimsIdentity 重新赋值
services.Configure<ClaimsIdentityOptions>(options =>
{
options.UserIdClaimType = "与 User.Claims 中的 id 一致";
});