使用OWIN Identity v2声明来跟踪WebAPI2应用程序中的自定义属性



让我的头包裹在新的身份框架,我试图找出如何最好地处理自定义用户属性。我已经尝试扩展IdentityUser,它可以存储信息,但到目前为止需要额外的db调用才能将属性取出。我正在考虑切换到使用声明来存储/检索此信息。

首先,我想要存储/检索的特定道具不是单个用户所独有的(多对一)。考虑在自定义Group结构中将用户分组在一起。我想存储GroupId以便在其他相关实体中使用。

我能够存储GroupId(目前使用ClaimTypes)。NameIdentifier,我不认为这是该类型的正确用法,但是…)。但是,当我去检索该值时,在索赔集合中找不到索赔类型。它在数据库里,所以我知道它在那里。我错过了一些东西

fww:因为它是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返回一个空值时,当试图获取Value时错误发生

任何提示或更好的/最佳实践在这里将不胜感激!老实说,我更愿意将其存储在ApplicationUser : IdentityUser对象上,但我找不到检索User对象的简单方法。在我的api控制器上下文中,不需要额外调用db.

您对存储额外数据作为声明的直觉是正确的,但是实现有点坏。

我建议为您的域信息创建您自己的索赔类型。不要重用框架提供的声明类型。原因是ClaimTypes.NameIdentifier代表User.Id。框架本身为所有用户添加标准声明列表:

  • 用户。Id =>表示为ClaimTypes.NameIdentifier
  • Username =>表示为"ClaimTypes"。"
  • ProviderName =>表示为ClaimTypes.ProviderName(对此不是100%确定);通常值是"ASP"。网络身份"
  • SecurityStamp值(不确定它的声明类型名称)
  • 分配给用户的所有角色存储为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;
}

对于扩展方法,我通常使用IPrincipalClaimsPrincipal。但IIdentity也是可行的。别忘了你可以在任何地方通过调用ClaimsPrincipal.Current来访问ClaimsPrincipal

我通常是这样处理扩展方法的:

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();

希望这澄清你的困惑!

相关内容

  • 没有找到相关文章

最新更新