複数の役割を持つ属性を承認する


97

一度に複数のロールの承認をコントローラーに追加したいと思います。

通常は次のようになります。

[Authorize(Roles = "RoleA,RoleB,RoleC")]
public async Task<ActionResult> Index()
{
}

しかし、ロールはある時点で変更または拡張される可能性があるため、constに保存しました。

public const RoleA = "RoleA";
public const RoleB = "RoleB";
public const RoleC = "RoleC";

文字列はコンパイル時に認識されている必要があるため、これはできません。

[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)]
public async Task<ActionResult> Index()
{
}

問題を回避する方法はありますか?

私は単に「RoleA、RoleB、RoleC」を含むconstを書くことができますが、私は魔法の文字列が嫌いで、これは魔法の文字列です。ロールの名前を変更し、結合された文字列を変更するのを忘れると、大変なことになります。

MVC5を使用しています。ASP.NETのIDとロールはコンパイル時に認識されます。


public const string RoleA = "RoleA"を使用していますか。またはあなたが問題に書いたように?
Mukesh Modhvadiya 2014年

回答:


188

このようなカスタム認証属性を作成してみてください。

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = string.Join(",", roles);
    }
}

複数のコントローラーで役割が同じになると想定して、ヘルパークラスを作成します。

public static class Role
{
    public const string Administrator = "Administrator";
    public const string Assistant = "Assistant";
}

次に、次のように使用します。

public class MyController : Controller
{
    [AuthorizeRoles(Role.Administrator, Role.Assistant)]
    public ActionResult AdminOrAssistant()
    {                       
        return View();
    }
}

12
さて、それはMac Gyverにふさわしいアイデアです;)
Christian Sauer

2
非常に素晴らしい解決策:)
aup

1
特に、自分のRoleを文字列ではなく列挙型にすることができるため、このソリューションも非常に気に入っています。このカスタム認証属性を配置するためのプロジェクト階層内の適切な名前空間と場所は何ですか?
Simon Shine

4
ここで何が起こっているのかはわかりませんが、これは役に立ちませんでした。役割に関係なく、どのユーザーもメソッドにアクセスできました。
Urielzen 2016年

2
@Urielzenと同じ問題ですが、Jerry Fineganからの以下の回答で修正されました(「System.Web.Mvc.AuthorizeAttributeおよびNOT System.Web.Http.AuthorizeAttribute」を使用)
RJB

13

あなたは離れてあなたのカスタム属性クラスを派生していることを確認しますSystem.Web.Mvc.AuthorizeAttributeとNOT System.Web.Http.AuthorizeAttribute

私は同じ問題に出くわしました。一度変更すると、すべてが機能しました。

カスタム属性クラスに以下を追加することもできます。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 

私はこれを試してみました、ライブラリを参照したSystem.Web.Http.AuthorizeAttributeINSTEAD OFSystem.Web.Mvc.AuthorizeAttribute
フレーザージョーダン

10

この問題を解決するために見つけた最善かつ最も簡単な方法は、Authorize属性でロールを連結することです。

[Authorize(Roles = CustomRoles.Admin + "," + CustomRoles.OtherRole)]

CustomRoleを使用して、次のような定数文字列を持つクラス:

public static class CustomRoles
{
    public const string Admin = "Admin";
    // and so on..
}

2
価値がある; しかし、これはコメントであるべきです。答えではありません。
GhostCat 2017年

1
シンプルでエレガントなソリューション!
Iosif Bancioiu 2017年

正しく実装されていれば、回答と承認された回答の両方が承認をトリガーします(私は本番環境のWebアプリで承認を使用しています)。承認された回答に関するコメントを削除する編集を提案します。
Eric Eskildsen、2018年

3

私がしたことは@Tiesonの答えです

私は彼の答えを少し調整しました。string.Joinの代わりに、なぜリストに変換しませんか?

これが私の答えです:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    private new List<string> Roles;
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = roles.toList()
    }
}

そして、役割がOnAuthorizationをオーバーライドして有効かどうかを確認します

public override void OnAuthorization(HttpActionContext actionContext)
{
            if (Roles == null)
                HandleUnauthorizedRequest(actionContext);
            else
            {
                ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
                string _role = claimsIdentity.FindFirst(ClaimTypes.Role).Value;
                bool isAuthorize = Roles.Any(role => role == _role);

                if(!isAuthorize)
                    HandleUnauthorizedRequest(actionContext);
            }
        }

これで、ロールにリソースへのアクセスが許可されているかどうかが検証されました


1

大量のロールがない限り、この問題に対してカスタムのauthorize属性はやり過ぎだと思います。

文字列はコンパイル時に既知でなければならないので、定義したロールのパブリック文字列を含む静的なRoleクラスを作成してから、認証する特定のロールを含むコンマ区切りの文字列を追加してください。

public static class Roles
{
    public const string ADMIN = "Admin";
    public const string VIEWER = "Viewer";

    public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}

次に、コントローラクラスまたはコントローラメソッド(またはその両方)でAuthorize Attributeを使用できます。

[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
    [Authorize(Roles = Roles.ADMIN_OR_VIEWER)
    public ActionResult Create()
    {
        ..code here...
    }
}

1
この例は機能しないか、少なくともあなたの考えている方法では機能しません。たとえば、小説ADMIN_OR_VIEWERではアクションの役割は冗長ですが、まだ役割をCreate持っていない場合、メソッドにアクセスすることはできませんADMIN。この場合、メソッドVIEWERを呼び出すことはできませんCreate
John Leidegren、2017年

このソリューションもスケーラブルではありません。さまざまなアクションを持つ役割が多すぎて、すべての組み合わせを作成するべきではない点があるでしょう
EduLopez
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.