我有一个使用Typescript实现的单页面应用程序的场景,它使用oidc-client从使用IdentityServer4的AspNet Core应用程序获取id_token和access_token。
在身份服务器上我也使用Identity与EntityFramework,以便我可以检索用户及其个人资料以生成声明等。
我正面临一种奇怪的情况,例如我为用户更新FirstName
,它在数据库中正确更新,但在生成用户级声明时given_name
,family_name
,name
和email
)given_name未使用新名称更新,因此发出的id_token不包含声明中的更新信息。
我有这样的事情:
public class AspNetIdentityProfileService : IProfileService
{
private readonly UserManager<User> _userManager;
private readonly IUserRepository _userRepository;
public AspNetIdentityProfileService(UserManager<User> userManager, IUserRepository userRepository)
{
_userManager = userManager;
_userRepository = userRepository;
}
// some code where I generate a List<Claim> calling below method
private async Task<IEnumerable<Claim>> GetUserLevelClaimsAsync(User user)
{
//user contains the updated info because it comes from DB.
List<Claim> userClaims = new List<Claim>();
var standardClaims = await _userManager.GetClaimsAsync(user); //has old values
userClaims.AddRange(standardClaims);
userClaims.Add(new Claim(JwtClaimTypes.Role, user.Role.ToString().ToLowerInvariant()));
return userClaims;
}
}
为什么await _userManager.GetClaimsAsync(user);
会忽略用户的更新信息? 从哪里获取旧信息?
我已经重新启动了应用程序,删除了浏览器cookie,以防它存储在身份服务器为单点登录目的而发出的cookie中。但我仍然不知道旧信息的缓存位置。
更新1 : 这是用户模型。
public class User : IdentityUser
{
//Extend properties
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public Guid? PrimaryBusinessId { get; set; }
public Business PrimaryBusiness { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get
{
return string.Join(" ", FirstName, LastName);
}
}
public DateTime? LastLoggedInOn { get; set; }
public UserRole Role { get; set; }
public List<UserBusiness> UserBusinesses { get; set; }
}
更新2 : 有一个明显的解决方法,即从User属性手动添加声明,而不是依赖Identity的UserManager。但问题仍然存在,为什么userManager不检索DB中的更新值?它在哪里找到检索到的旧值?
private IEnumerable<Claim> GetUserLevelClaims(User user)
{
List<Claim> userClaims = new List<Claim>();
//var standardClaims = await _userManager.GetClaimsAsync(user); //does not retrieve updated fields
userClaims.Add(new Claim(JwtClaimTypes.Name, user.FullName));
userClaims.Add(new Claim(JwtClaimTypes.FamilyName, user.LastName));
userClaims.Add(new Claim(JwtClaimTypes.GivenName, user.FirstName));
userClaims.Add(new Claim(JwtClaimTypes.Email, user.Email));
userClaims.Add(new Claim(JwtClaimTypes.Role, user.Role.ToString().ToLowerInvariant()));
return userClaims;
}
答案 0 :(得分:2)
您需要告诉IProfileService
从何处获取声明。
基本上来自userManager
的{{1}}只会获得该用户的相关声明。也就是IdentityUser.Claims。旧的价值观&#34;仍然存在于AspNetCore.Identity
表中。如果您针对该表中的任何声明更新该用户的关联实体,那么AspNetUserClaims
将发出这些更新的声明,因为您依靠IProfileService
来获取您的声明。
基本上要找出哪些声明属于某个用户,您可以看到有根表&#39;叫userManager
。此表有一个名为AspNetUsers
的称为表的关联声明。此表仅映射用户及其1-M声明。简而言之,您需要在该表中编辑声明值。
可以在AspNetUserClaims
的{{1}}中添加更多声明。基于表实体本身进一步添加声明是很常见的。正如您在更新#2中所展示的那样
答案 1 :(得分:1)
@Lutando用他的评论向我指出了正确的方向。
要回答我自己的问题,用户管理器不是从User表中获取声明,而是从另一个名为UserClaims的Identity表中获取声明。 我不知道这张桌子正在使用,但现在它才有意义。
正如Lutando所说,解决方法完全有效,我不需要依赖Identity的用户管理器来生成声明。我甚至不需要使用此UserClaims表,因为我的名称和姓氏是我的User表的一部分,如Update 1所示。