如何从ClaimsPrincipal中删除现有声明?

时间:2014-03-21 22:36:55

标签: c# asp.net-web-api wif claims-based-identity

我正在制作一个开发人员工具,用于模拟内联网网站的Roles,以便开发人员可以根据需要快速充当Role。定义的角色为Developer, Team Lead, Team Member, Engineering, Marketing, Guest,网页上的工具会调用Web Api来添加或删除Claim ......我可以添加,但似乎无法找到{可以访问{1}}或.RemoveClaim(claim)以使其正常工作。我是否必须创建自定义声明管理器才能获得此功能,或者我是否遗漏了某些内容?

我一直在关注System.Security.Claims,几乎所有其他事情似乎都非常简单,并且没有提及需要大量工作来做我需要的事情。

我在.NET 4.5.1中使用VS 2013 / Web Api2。

网站方只是使用简单的ajax调用.TryRemoveClaim(claim)PUT功能,直到我按照我想要的方式工作。在Controller中,我的cs代码如下:

DELETE

public void Put(int id, [FromBody]string role) { if (FindClaim(role) != null) return; var user = HttpContext.Current.User as ClaimsPrincipal; if (user == null) return; var claimId = new ClaimsIdentity(); claimId.AddClaim(new Claim(ClaimTypes.Role, role)); user.AddIdentity(claimId); } // DELETE api/devroleadjuster/5 public void Delete(int id, [FromBody]string role) { var claim = FindClaim(role); if (claim == null) return; var user = HttpContext.Current.User as ClaimsPrincipal; if (user == null) return; // Why can't I do this???? user.RemoveClaim(claim); } private Claim FindClaim(string role) { try { var user = HttpContext.Current.User as ClaimsPrincipal; var claim = (from c in user.Claims where c.Value == role select c).Single(); return claim; } catch (InvalidOperationException) { return null; } } 工作得很好,问题在于我的代码的Put部分......我想使用Delete代码或类似代码...我可以我明白为什么我不能根据MSDN,我找不到任何删除声明的示例代码。

3 个答案:

答案 0 :(得分:33)

您应该使用标识来添加或删除声明。试试这个来添加声明。

var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
identity.AddClaim(new Claim(ClaimTypes.Role, "somenewrole"));

要删除声明,

var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
var claim = (from c in user.Claims
                         where c.Value == "somenewrole"
                         select c).Single();
identity.RemoveClaim(claim);
顺便说一句,最好使用控制器中的User而不是HttpContext.Current.User

答案 1 :(得分:5)

要添加的其他重要信息是确保您不会尝试迭代声明集合并删除项目。我只是偶然发现了别人写的错误代码,起初我没有看到问题,直到我介入它。

有缺陷的代码是:

        foreach (var claim in identity.Claims)
        {
            var name = claim.Type;
            if (!name.Equals("UserAccountId") && !name.Equals("Email") && !name.Equals("TenantIds"))
            {
                identity.RemoveClaim(claim);
            }
        }

结果是声明从列表中不一致地删除。问题的简单解决方案是迭代索赔列表而不是索赔本身,并以这种方式删除它们:

        var claimNameList = identity.Claims.Select(x => x.Type).ToList();

        foreach (var name in claimNameList)
        {
            if (!name.Equals("UserAccountId") && !name.Equals("Email") && !name.Equals("TenantIds"))
            {
                var claim = identity.Claims.FirstOrDefault(x => x.Type == name);
                if (claim != null)
                    identity.RemoveClaim(claim);
            }
        }

迭代集合并添加或删除项目绝不是一个好主意。您将看到偶发错误和不同结果,具体取决于具体情况,在某些情况下,例如迭代HttpContext.Current.Items中的项目,您将看到有关正在修改的集合的零星错误。

答案 2 :(得分:0)

找到用户然后将其删除。

var user = await _userManager.FindByIdAsync(userId);
var claim =  _userManager.GetClaimsAsync(user).Result.FirstOrDefault(c => c.Type == claimType);
var result =await _userManager.RemoveClaimAsync(user, claim);