Ermöglichen Sie mehreren Rollen den Zugriff auf Controller-Aktionen

274

Im Moment dekoriere ich eine Methode wie diese, damit "Mitglieder" auf meine Controller-Aktion zugreifen können

[Authorize(Roles="members")]

Wie erlaube ich mehr als eine Rolle? Zum Beispiel funktioniert Folgendes nicht, aber es zeigt, was ich versuche (Zugriff für "Mitglieder" und "Administrator" zulassen):

[Authorize(Roles="members", "admin")] 
Codette
quelle
4
Bitte ändern Sie die akzeptierte Antwort auf diese Frage. Die Person mit der aktuell akzeptierten Antwort hat sie bearbeitet und darauf hingewiesen, dass sie sich geirrt hat.
Eric J.

Antworten:

595

Eine andere Möglichkeit besteht darin, einen einzelnen Autorisierungsfilter zu verwenden, während Sie Beiträge veröffentlichen, aber die inneren Anführungszeichen zu entfernen.

[Authorize(Roles="members,admin")]
Jim Schmehil
quelle
5
Funktioniert auch in MVC 5. +1
gkonuralp
4
Funktioniert in ASP.NET Core 1.0 (MVC 6) und Microsoft.AspNet.Identity v3. *
Soren
3
Dies ist in Ordnung, wenn Sie nur einen Controller haben, den Sie autorisieren müssen. Wenn Sie mehr als eine haben, duplizieren Sie diese Zeichenfolgenkonstanten (yuck). Ich bevorzuge die statische Klasse mit den Rollennamen. Mein Haustier Hass ist doppelte Zeichenfolgen ... so schlecht.
Robnick
1
@kraeg gute Nachricht, dass Sie Ihr Problem gelöst haben. Löschen Sie jetzt bitte Ihre Kommentare
Pablo Claus
1
Warum? Ich habe ewig gebraucht, um das herauszufinden. Dies kann für andere Personen hilfreich sein, bei denen das gleiche Problem auftritt.
Kraeg
128

Wenn Sie benutzerdefinierte Rollen verwenden möchten, können Sie dies tun:

CustomRoles Klasse:

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

Verwendung

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

Wenn Sie nur wenige Rollen haben, können Sie diese möglicherweise (aus Gründen der Übersichtlichkeit) folgendermaßen kombinieren:

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

Verwendung

[Authorize(Roles = CustomRoles.AdministratorOrUser)]
Pablo Claus
quelle
7
Dies wäre eine gute Antwort, wenn Sie Leuten erklären würden, die nicht wissen, was hinter CustomRoles steckt.
James Skemp
1
@ JamesSkemp ok, ich habe meine Antwort erweitert. Es ist sehr einfach. CustumRoles ist eine von mir erstellte Klasse, die einige Konstanten enthält, die meinen Anwendungsrollen entsprechen. Ich habe das aus mehreren Gründen getan: 1) Es ermöglicht die Verwendung von Intellisense, um Rechtschreibfehler zu vermeiden. 2) Um die Wartung zu vereinfachen. Wenn sich eine Rolle ändert, muss ich nur eine Stelle in meiner Anwendung aktualisieren.
Pablo Claus
@Pabloker Alternativ können Sie eine Aufzählung mit einem Flags-Attribut erstellen, z. B. Convert.ToString (CustomRoles.Administrator | CustomRoles.User). - ärgerlicher Teil ist, dass dies eine explizite Konvertierung erfordert
cstruter
Wenn Sie 39 Rollen haben?
Kiquenet
Ich denke, Ihr Problem geht durch die Modellierung von Genehmigungen über das hinaus, was mit .net gemacht werden kann
Pablo Claus
81

Eine mögliche Vereinfachung wäre die Unterklasse AuthorizeAttribute:

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

Verwendungszweck:

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

Semantisch ist es dasselbe wie Jim Schmehils Antwort.

Mihkel Müür
quelle
3
Dies hat bei mir nicht funktioniert. Der angemeldete Benutzer konnte das Attribut umgehen, auch wenn der Benutzer keine der Rollen hatte.
Urielzen
8
Diese Antwort ist besser für, wenn Sie Konstanten als Ihre Werte verwenden: dh [Rollen (Constants.Admin, Constants.Owner)]
Dalcam
2
Dies ist die beste Antwort
IgorShch
18

Für MVC4 verwende ich ein Enum( UserRoles) mit meinen Rollen und eine benutzerdefinierte AuthorizeAttribute.

Bei meiner kontrollierten Aktion mache ich:

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

Und ich benutze einen solchen Brauch 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;
        }
    }
}

Dies ist Teil des modifizierten FNHMVC von Fabricio Martínez Tamayo https://github.com/fabriciomrtnz/FNHMVC/

Bernardo Loureiro
quelle
1
Für Ihre OnAuthorization-Methode muss der Benutzer über alle aufgezählten Rollen verfügen . War das beabsichtigt, oder fehlt Ihnen eine Unterbrechung in dieser Schleife?
Tieson T.
@Tieson: Ich habe das ziemlich genau untersucht, es scheint definitiv, dass eine Pause in dieser Schleife erforderlich wäre.
OcelotXL
@ TiesonT. und @ madrush, ich schätze deine Lösung, es könnte wirklich eine Pause in der Schleife geben. Ich werde den Code oben ändern.
Bernardo Loureiro
Die Aufzählung UserRoles ist nett. Deklarieren Sie es manuell oder wird es basierend auf dem Inhalt der Datenbank automatisch generiert?
Konrad Viltersten
@KonradViltersten Es ist manuell, aber ich denke, mit Reflection und Dynamic Klasse kann automatisch generiert werden
Bernardo Loureiro
3

Eine weitere klare Lösung: Sie können Konstanten verwenden, um die Konvention beizubehalten und mehrere [Authorize] -Attribute hinzuzufügen. Überprüfen Sie dies heraus:

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

Dann in der Steuerung:

[Authorize(Roles = RolesConvention.Administrator )]
[Authorize(Roles = RolesConvention.Guest)]
[Produces("application/json")]
[Route("api/[controller]")]
public class MyController : Controller
Renê R. Silva
quelle
14
Mehrere AuthorizeAttribute verwenden UND-Semantik und erfordern, dass ALLE Bedingungen erfüllt sind (dh der Benutzer muss sich sowohl in der Administrator- als auch in der Gastrolle befinden).
Trousyt
3

Wenn Sie diese beiden Rollen häufig anwenden, können Sie sie in ihre eigene Berechtigung einschließen. Dies ist wirklich eine Erweiterung der akzeptierten Antwort.

using System.Web.Mvc;

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

Wenden Sie dann Ihre neue Berechtigung auf die Aktion an. Ich denke, das sieht sauberer aus und liest sich leicht.

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

Besserer Code durch Hinzufügen einer Unterklasse 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 }
                  }
              );
            }
        }
    }

Wie man das benutzt

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

public ActionResult Index()
{
return View();
}
kinzzy goel
quelle
1

Mit AspNetCore 2.x müssen Sie einen etwas anderen Weg gehen:

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

benutze es einfach so:

[Authorize(YourEnum.Role1, YourEnum.Role2)]
Daniel DirtyNative Martin
quelle
-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);
Orsit Moel
quelle
1
Antworten einschließlich Code sollten mindestens eine Mindestbeschreibung enthalten, in der erläutert wird, wie der Code funktioniert und warum er auf die Frage antwortet. Im weiteren Modus muss die Formatierung des Codeabschnitts verbessert werden.
Roberto Caboni
Huh? @ Orsit Moel, sieht aus wie in einen falschen Thread eingefügt ...
Cameron Forward