複数の役割がコントローラーアクションにアクセスできるようにする


274

現在、このようなメソッドを装飾して、「メンバー」がコントローラーアクションにアクセスできるようにしています

[Authorize(Roles="members")]

複数の役割を許可するにはどうすればよいですか?たとえば、次は機能しませんが、私がやろうとしていることを示しています(「メンバー」と「管理者」アクセスを許可します)。

[Authorize(Roles="members", "admin")] 

4
この質問に対する承認済みの回答を変更してください。現在受け入れられている回答のある人がそれを編集して、彼が間違っていることを示しました。
エリックJ.

回答:


595

別のオプションは、投稿時に単一の承認フィルターを使用するが、内部の引用を削除することです。

[Authorize(Roles="members,admin")]

5
MVC 5でも動作します。+1
gkonuralp 2015

4
ASP.NET Core 1.0(MVC 6)およびMicrosoft.AspNet.Identity v3。*で動作します
Soren

3
承認が必要なコントローラが1つしかない場合は、これで問題ありません。複数ある場合は、それらの文字列定数を複製しています(yuck)。私は、ロール名を持つ静的クラスを好みます。私のペットの憎しみは文字列の重複です...とても悪い
ロブニック2018

1
@kraegあなたがあなたの問題を解決した良いニュース。今、あなたのコメントを削除することを検討してください
パブロ・クラウス

1
どうして?これを解決するのに何年もかかりました。同じ問題が発生している他のユーザーにとって役立つ場合があります。
kraeg

129

カスタムの役割を使用する場合は、次のようにします。

CustomRoles クラス:

public static class CustomRoles
{
    public const string Administrator = "Administrador";
    public const string User = "Usuario";
}

使用法

[Authorize(Roles = CustomRoles.Administrator +","+ CustomRoles.User)]

役割が少ない場合は、次のようにそれらを(明確にするために)組み合わせることができます。

public static class CustomRoles
{
     public const string Administrator = "Administrador";
     public const string User = "Usuario";
     public const string AdministratorOrUser = Administrator + "," + User;  
}

使用法

[Authorize(Roles = CustomRoles.AdministratorOrUser)]

7
CustomRolesの背後にあるものを知らない人に説明した場合、これは良い答えになります。
James Skemp

1
@JamesSkempわかりました、私は私の答えを拡張しました。とてもシンプルです。CustumRolesは、アプリケーションの役割に対応するいくつかの定数を含む、私が作成したクラスです。私はいくつかの理由でそれをしました:1)スペルミスを避けるためにインテリセンスの使用を可能にします2)メンテナンスを簡素化します。ロールが変更された場合、アプリケーション内の1つの場所のみを更新する必要があります。
パブロクラウス

@Pabloker別の方法として、Convert.ToString(CustomRoles.Administrator | CustomRoles.User);などのFlags属性を使用して列挙型を作成することもできます。-迷惑な部分は、これには明示的な変換が必要であることです
cstruter

39の役割がある場合?
Kiquenet

あなたの問題は、.netでできることを超えて許可のモデリングを通過していると思います
Pablo Claus

82

可能な単純化の1つは、サブクラス化することAuthorizeAttributeです。

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

使用法:

[Roles("members", "admin")]

意味的にはジムシュメヒルの答えと同じです。


3
これは私にとってはうまくいきませんでした。ログインしているユーザーは、ユーザーに役割がなくても属性をバイパスできました。
Urielzen 2016年

9
この答えは、値として定数を使用している場合に適しています。つまり、[Roles(Constants.Admin、Constants.Owner)]
dalcam '23

3
これが最良の答えです
IgorShch 2018

18

MVC4の場合、自分の役割でEnumUserRoles)を使用して、カスタムを使用しますAuthorizeAttribute

私の制御されたアクションで、私はします:

[CustomAuthorize(UserRoles.Admin, UserRoles.User)]
public ActionResult ChangePassword()
{
    return View();
}

そして、私はそのAuthorizeAttributeようなカスタムを使用します:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorize : AuthorizeAttribute
{
    private string[] UserProfilesRequired { get; set; }

    public CustomAuthorize(params object[] userProfilesRequired)
    {
        if (userProfilesRequired.Any(p => p.GetType().BaseType != typeof(Enum)))
            throw new ArgumentException("userProfilesRequired");

        this.UserProfilesRequired = userProfilesRequired.Select(p => Enum.GetName(p.GetType(), p)).ToArray();
    }

    public override void OnAuthorization(AuthorizationContext context)
    {
        bool authorized = false;

        foreach (var role in this.UserProfilesRequired)
            if (HttpContext.Current.User.IsInRole(role))
            {
                authorized = true;
                break;
            }

        if (!authorized)
        {
            var url = new UrlHelper(context.RequestContext);
            var logonUrl = url.Action("Http", "Error", new { Id = 401, Area = "" });
            context.Result = new RedirectResult(logonUrl);

            return;
        }
    }
}

これは、FabricioMartínezTamayoによって変更されたFNHMVCの一部ですhttps://github.com/fabriciomrtnz/FNHMVC/


1
OnAuthorizationメソッドでは、ユーザーは列挙されたすべてのロールを持っている必要があります。それは意図的なものでしたか、それともそのループの中断を逃していますか?
Tieson T.

@Tieson:私はそれをかなり綿密に調査しました、そのループではブレークが必要になるように思われます。
OcelotXL 2015年

@TiesonT。と@ madrush、私はあなたの修正に感謝します、それは本当にループの内側でブレークを持っている可能性があります。上記のコードを変更します。
Bernardo Loureiro、2015年

列挙型UserRolesは素晴らしいです。手動で宣言しますか、それともDBの内容に基づいて自動生成しますか?
Konrad Viltersten、2016年

@KonradVilterstenそれは手動ですが、リフレクションと動的クラスで自動生成できると思います
Bernardo Loureiro

3

別の明確な解決策は、定数を使用して規則を守り、複数の[Authorize]属性を追加することです。これをチェックしてください:

public static class RolesConvention
{
    public const string Administrator = "Administrator";
    public const string Guest = "Guest";
}

次にコントローラーで:

[Authorize(Roles = RolesConvention.Administrator )]
[Authorize(Roles = RolesConvention.Guest)]
[Produces("application/json")]
[Route("api/[controller]")]
public class MyController : Controller

14
複数のAuthorize属性はANDセマンティクスを使用し、すべての条件を満たす必要があります(つまり、ユーザーは管理者ロールとゲストロールの両方に属している必要があります)。
trousyt 2017年

3

これらの2つのロールを頻繁に適用している場合は、それらを独自の承認でラップできます。これは本当に受け入れられた答えの延長です。

using System.Web.Mvc;

public class AuthorizeAdminOrMember : AuthorizeAttribute
{
    public AuthorizeAdminOrMember()
    {
        Roles = "members, admin";
    }
}

次に、新しい承認をアクションに適用します。これは見た目がきれいで読みやすいと思います。

public class MyController : Controller
{
    [AuthorizeAdminOrMember]
    public ActionResult MyAction()
    {
        return null;
    }
}

1

サブクラスを追加してコードを改善する AuthorizeRole.cs

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    class AuthorizeRoleAttribute : AuthorizeAttribute
    {
        public AuthorizeRoleAttribute(params Rolenames[] roles)
        {
            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
        protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Unauthorized" },
                  { "controller", "Home" },
                  { "area", "" }
                  }
              );
                //base.HandleUnauthorizedRequest(filterContext);
            }
            else
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Login" },
                  { "controller", "Account" },
                  { "area", "" },
                  { "returnUrl", HttpContext.Current.Request.Url }
                  }
              );
            }
        }
    }

これの使い方

[AuthorizeRole(Rolenames.Admin,Rolenames.Member)]

public ActionResult Index()
{
return View();
}

1

AspNetCore 2.xを使用して、少し異なる方法を実行する必要があります。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeRoleAttribute : AuthorizeAttribute
{
    public AuthorizeRoleAttribute(params YourEnum[] roles)
    {
        Policy = string.Join(",", roles.Select(r => r.GetDescription()));
    }
}

次のように使用してください:

[Authorize(YourEnum.Role1, YourEnum.Role2)]

-2
Intent promptInstall = new Intent(android.content.Intent.ACTION_VIEW);
promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
promptInstall.setDataAndType(Uri.parse("http://10.0.2.2:8081/MyAPPStore/apk/Teflouki.apk"), "application/vnd.android.package-archive" );

startActivity(promptInstall);

1
コードを含む回答には、コードがどのように機能するか、なぜコードが質問に回答するのかを説明する最低限の説明が必要です。さらに、コードセクションの書式設定を改善する必要があります。
Roberto Caboni

え?@Orsit Moel、コピーが間違ったスレッドに貼り付けられたように見える...
キャメロンフォワード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.