簡體   English   中英

使用OWIN Identity v2聲明來跟蹤WebAPI2應用程序中的自定義屬性

[英]Using OWIN Identity v2 Claims to track custom properties in WebAPI2 app

讓我的腦袋圍繞新的身份框架,並試圖找出如何最好地處理自定義用戶屬性。 我已經嘗試擴展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;
    }

嘗試獲取Value時錯誤命中,因為FindFirst返回空值。

這里的任何提示或更好/最佳實踐將不勝感激! 老實說,我更願意將它存儲在ApplicationUser : IdentityUser對象上,但我找不到一種簡單的方法來檢索我的api控制器上下文中的User.Identity,而無需額外調用db。

您對將額外數據存儲為聲明的直覺感覺是正確的,但實現有點破碎。

我建議您為自己的域信息創建自己的聲明類型。 不要重用框架提供的聲明類型。 原因是ClaimTypes.NameIdentifier代表User.Id. 該框架本身為所有用戶添加了標准的聲明列表:

  • User.Id =>表示為ClaimTypes.NameIdentifier
  • Username =>表示為'ClaimTypes.Name'
  • ProviderName =>表示為ClaimTypes.ProviderName (不是100%肯定這個); 通常值是“ASP.NET身份”
  • 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通過調用任何地方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();

希望這能澄清你的困惑!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM