AspNet Identity 如何生成用户声明
How AspNet Identity generates user claims
我有一个使用 Typescript 实现的单页应用程序的场景,它使用 oidc-client 从使用 IdentityServer4 的 AspNet Core 应用程序获取 id_token 和 access_token。
在身份服务器上,我也在 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:
有一个明显的解决方法,即从用户属性手动添加声明,而不是依赖于身份的 UserManager。但问题仍然存在,为什么 userManager 不检索数据库中的更新值?它在哪里找到检索到的旧值?
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;
}
@Lutando 用他的评论为我指明了正确的方向。
为了回答我自己的问题,用户管理器不是从用户 table 获取声明,而是从另一个名为 UserClaims 的身份 table 获取声明。
我不知道这个 table 被使用了,但现在它有意义了。
正如 Lutando 还建议的那样,解决方法完全有效,我不需要依赖身份的用户管理器来生成声明。我什至不需要使用此 UserClaims table,因为我的用户 table 中有姓名和姓氏,如更新 1 中所示。
您需要告诉 IProfileService
从哪里获得声明。
基本上来自 AspNetCore.Identity
的 userManager
只会获得该用户的相关声明。即IdentityUser.Claims。 "old values" 仍然存在于 AspNetUserClaims
table 中。如果您为 table 中的任何声明更新该用户的关联实体,那么 IProfileService
将发布这些更新的声明,因为您依赖 userManager
来获取您的声明。
基本上,要找出属于用户的声明,您可以看到有一个名为 AspNetUsers
的 'root table'。此 table 有一个名为 table 的关联声明,名为 AspNetUserClaims
。此 table 仅映射用户及其 1-M 声明。简而言之,您需要编辑 table 中的声明值。
随时向 GetProfileDataAsync
中的 IProfileService
添加更多声明。基于 table 实体本身进一步添加声明是很常见的。正如您在更新 #2
中所展示的那样
我有一个使用 Typescript 实现的单页应用程序的场景,它使用 oidc-client 从使用 IdentityServer4 的 AspNet Core 应用程序获取 id_token 和 access_token。
在身份服务器上,我也在 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: 有一个明显的解决方法,即从用户属性手动添加声明,而不是依赖于身份的 UserManager。但问题仍然存在,为什么 userManager 不检索数据库中的更新值?它在哪里找到检索到的旧值?
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;
}
@Lutando 用他的评论为我指明了正确的方向。
为了回答我自己的问题,用户管理器不是从用户 table 获取声明,而是从另一个名为 UserClaims 的身份 table 获取声明。 我不知道这个 table 被使用了,但现在它有意义了。
正如 Lutando 还建议的那样,解决方法完全有效,我不需要依赖身份的用户管理器来生成声明。我什至不需要使用此 UserClaims table,因为我的用户 table 中有姓名和姓氏,如更新 1 中所示。
您需要告诉 IProfileService
从哪里获得声明。
基本上来自 AspNetCore.Identity
的 userManager
只会获得该用户的相关声明。即IdentityUser.Claims。 "old values" 仍然存在于 AspNetUserClaims
table 中。如果您为 table 中的任何声明更新该用户的关联实体,那么 IProfileService
将发布这些更新的声明,因为您依赖 userManager
来获取您的声明。
基本上,要找出属于用户的声明,您可以看到有一个名为 AspNetUsers
的 'root table'。此 table 有一个名为 table 的关联声明,名为 AspNetUserClaims
。此 table 仅映射用户及其 1-M 声明。简而言之,您需要编辑 table 中的声明值。
随时向 GetProfileDataAsync
中的 IProfileService
添加更多声明。基于 table 实体本身进一步添加声明是很常见的。正如您在更新 #2