web-dev-qa-db-ja.com

複数のロールで属性を認証する

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

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

[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とロールは、コンパイル時に既知です。

83
Christian Sauer

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

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();
    }
}
163
MacGyver

System.Web.Mvc.AuthorizeAttributeではなくSystem.Web.Http.AuthorizeAttributeからカスタム属性クラスを派生していることを確認してください。

私は同じ問題に遭遇しました。変更すると、すべてが機能しました。

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

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

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

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

customRoleの場合、次のような定数文字列を持つクラス:

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

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

私は彼の答えを少し調整しました。文字列の代わりに、リストに変換してみませんか?

私の答えは次のとおりです。

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

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

大量の役割を持たない限り、カスタム認証属性はこの問題に対して過剰すぎると感じます。

文字列はコンパイル時に認識される必要があるため、定義したロールのパブリック文字列を含む静的な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...
    }
}
0
Robert Tuttle