【问题标题】:How do I remove an existing claim from a ClaimsPrinciple?如何从 ClaimsPrincipal 中删除现有的声明?
【发布时间】:2014-04-29 12:39:57
【问题描述】:

我正在为 Intranet 站点制作一个模拟 Roles 的开发人员工具,以允许开发人员根据需要快速充当任何 Role。定义的角色是Developer, Team Lead, Team Member, Engineering, Marketing, Guest 并且网页上的一个工具调用Web Api 以添加或删除Claim...我可以添加但似乎无法找出.RemoveClaim(claim) 或@ 的位置可以访问 987654327@ 以使其正常工作。我是否必须创建自定义索赔管理器才能获得此功能,还是我遗漏了什么?

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

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

网站端只使用简单的 ajax 调用 PUTDELETE 功能,直到我让它按我想要的方式工作。在Controller中,我的cs代码如下:

    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 部分...我想使用user.RemoveClaim(claim); 代码或类似的东西...我不明白为什么我可以'不是根据 MSDN,我找不到任何删除声明的示例代码。

【问题讨论】:

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


    【解决方案1】:

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

    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

    【讨论】:

    • 哎呀,很明显,现在你指出了它......有时我太接近这个问题而无法思考。 @Badri 有理由不使用 HttpContext.Current.User 吗?这是示例所显示的,所以如果有理由保持警惕,我想知道。提前致谢。
    • HttpContext 将您与网络托管紧密结合。最好使用User 属性形式的抽象。检查此链接 - aspnetwebstack.codeplex.com/workitem/1294,特别是 David Matson 的回复(搜索 davidmatson 于 2013 年 9 月 13 日晚上 9:18 写)。
    • 我在尝试使用身份删除声明时收到错误:The Claim 'time_zone_string: Mountain Standard Time' was not able to be removed. It is either not part of this Identity or it is a claim that is owned by the Principal that contains this Identity. For example, the Principal will own the claim when creating a GenericPrincipal with roles. The roles will be exposed through the Identity that is passed in the constructor, but not actually owned by the Identity. Similar logic exists for a RolePrincipal.
    • @Badri。你知道如何让它在页面加载之间持续存在吗?我的一直恢复到更改前的状态。
    • 无法删除声明“time_zone_string:山地标准时间”。它要么不是此身份的一部分,要么是包含此身份的委托人拥有的声明。例如,在创建具有角色的 GenericPrincipal 时,委托人将拥有声明。这可能会产生误导 - 对我来说,问题是缺少声明!
    【解决方案2】:

    要添加的其他重要内容是确保您不要尝试迭代声明集合并删除项目。我只是偶然发现了其他人编写的错误代码,一开始我没有发现问题,直到我逐步完成它。

    错误代码是:

            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 中的项目,您会看到关于正在修改的集合的零星错误。

    【讨论】:

      【解决方案3】:

      找到用户然后删除它。

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

      【讨论】:

        猜你喜欢
        • 2014-09-01
        • 2017-04-01
        • 2016-11-14
        • 1970-01-01
        • 1970-01-01
        • 2017-10-14
        • 2017-04-01
        • 2021-07-09
        • 1970-01-01
        相关资源
        最近更新 更多