让我的头脑围绕新的Identity框架,并试图找出如何最好地处理自定义用户属性。我已经尝试扩展IdentityUser,它可以存储信息,但到目前为止需要额外的db调用来恢复属性。我正在寻求使用声明来存储/检索此信息。
首先,我想要存储/检索的特定道具对于单个用户(多对一)并不是唯一的。考虑将用户组合在一个自定义组结构中。我想存储GroupId以用于其他相关实体。
我能够存储GroupId(目前使用的是ClaimTypes.NameIdentifier,我不认为它是该类型的正确用法,但是......)。但是,当我去检索该值时,声明集合中找不到声明类型。它在数据库中,所以我知道它就在那里。我错过了什么。
FWIW:因为它是WebAPI,所以我没有使用传统的登录方式。我正在使用令牌身份验证。
当我创建用户时,我有类似的东西:
public async Task<IdentityResult> CreateUserAsync(string email, string password, string groupId)
{
var userId = ObjectId.GenerateNewId(DateTime.UtcNow).ToString(); // yes, it's a NoSQL store
var user = new ApplicationUser
{
Id = userId,
UserName = email
};
var claim = new IdentityUserClaim { ClaimType = ClaimTypes.NameIdentifier, ClaimValue = groupId, UserId = userId, Id = ObjectId.GenerateNewId(DateTime.UtcNow).ToString() };
user.Claims.Add(claim);
var result = await _UserManager.CreateAsync(user, password);
return result;
}
这会创建一个看似合适的数据库条目。
当我检索该值时,我得到空引用错误。这是通过扩展方法的代码:
public static string GetGroupId(this IIdentity identity)
{
var claimsIdentity = identity as ClaimsIdentity;
return claimsIdentity == null ? "" : claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
}
当FindFirst返回空值时,错误在尝试获取值时命中。
此处的任何提示或更好/最佳做法将不胜感激!老实说,我更愿意将它存储在ApplicationUser : IdentityUser
对象上,但是我找不到一种简单的方法来检索我的api控制器上下文中的User.Identity而不需要额外调用db。
答案 0 :(得分:5)
您对将额外数据存储为声明的直觉感觉是正确的,但实施有点不妥。
我建议您为自己的域信息创建自己的声明类型。不要重用框架提供的声明类型。原因是ClaimTypes.NameIdentifier
代表User.Id.
该框架本身为所有用户添加了标准的声明列表:
ClaimTypes.NameIdentifier
ClaimTypes.ProviderName
(不是100%肯定这个);通常值是&#34; ASP.NET Identity&#34; ClaimTypes.Role
因此,在您的情况下,您尝试使用User.Id
的值来覆盖声明,这非常重要,我认为 - )
现在,让我们尝试解决您的编码问题。创建用户时,在创建用户对象后添加声明:
public async Task<IdentityResult> CreateUserAsync(string email, string password, string groupId)
{
var user = new ApplicationUser
{
Id = userId,
UserName = email
};
var userCreateResult = await _UserManager.CreateAsync(user, password);
if(!userCreateResult.IsSuccess)
{
// user creation have failed - need to stop the transaction
return userCreateResult;
}
// better to have a class with constants representing your claim types
var groupIdClaim = new Claim("MyApplication:GroupClaim", ObjectId.GenerateNewId(DateTime.UtcNow).ToString());
// this will save the claim into the database. Next time user logs in, it will be added to Principal.Identity
var claimAddingResult = await _UserManager.AddClaimAsync(userId, groupIdClaim);
return claimAddingResult;
}
对于扩展方法,我通常使用IPrincipal
或ClaimsPrincipal
。但是IIdentity
也是可行的。不要忘记您可以通过拨打ClaimsPrincipal
在任何地方访问ClaimsPrincipal.Current
。
这就是我通常使用扩展方法的方法:
public static string GetGroupId(this ClaimsPrincipal principal)
{
var groupIdClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApplication:GroupClaim");
if (personIdClaim != null)
{
return groupIdClaim.Value;
}
return String.Empty;
}
因此,在您的方法中,您可以为当前登录的用户检索分配的groupId
,如下所示:
var groupId = ClaimsPrincipal.Current.GetGroupId();
希望这能澄清你的困惑!