web-dev-qa-db-ja.com

ClaimsPrincipalから既存のクレームを削除するにはどうすればよいですか?

イントラネットサイトのRolesになりすまして、必要に応じてRoleとしてすばやく開発者が行動できるようにする開発者ツールを作成しています。定義されたロールはDeveloper, Team Lead, Team Member, Engineering, Marketing, Guestであり、Webページ上のツールがClaimを追加または削除するためにWeb APIを呼び出します...よく追加できますが、 .RemoveClaim(claim)または.TryRemoveClaim(claim)にアクセスして、これを機能させることができます。この機能を使用するにはカスタムクレームマネージャーを作成する必要がありますか、それとも何か不足していますか?

私は System.Security.Claims を見てきましたが、他のほとんどすべては非常に簡単に機能するようであり、必要なことを行うために広範な作業を必要とすることについての言及はありません。

.NET 4.5.1でVS 2013/Web Api2を使用しています。

Webサイト側では、PUTおよびDELETE機能への単純なajax呼び出しを使用して、これが希望どおりに機能するようになります。コントローラから、私の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でなぜこれができないのかわからないし、クレームを削除するためのサンプルコードも見つかりません。

26
Greg Mason

クレームを追加または削除するには、IDを使用する必要があります。申し立てを追加するには、これを試してください。

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

ところで、HttpContext.Current.Userではなく、コントローラからUserを使用することをお勧めします。

34
Badri

追加することが重要な他のことは、クレームのコレクションを反復してアイテムを削除しないようにすることです。私は誰か他の人が書いたバグのあるコードに偶然出会いましたが、最初は問題を突き止めるまで問題はわかりませんでした。

バグのあるコードは次のとおりです。

        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のアイテムを繰り返し処理する場合など、変更中のコレクションに関する散発的なエラーが表示されます。

5
David Spenard