Asp.net MVC4: Autorisierung sowohl für den Controller als auch für die Aktion

Antworten:

160

Du hast gefragt:

Wenn ich das Authorize-Attribut sowohl für den Controller als auch für die Aktion habe, welches wird den Effekt haben? Beide?

Um dies einfach zu beantworten: Beides. Der Effekt ist auf ANDdie beiden Einschränkungen zusammen. Ich werde unten erklären, warum ...

Einzelheiten

Es gibt also einige Gründe, warum Sie dies fragen könnten.

  1. Sie möchten wissen, wie Sie eine zusätzliche Einschränkung für eine Aktion im Vergleich zu einer Methode erzwingen können. z.B
    • Erzwingen Sie auf Controller-Ebene Benutzer in der Rolle "Benutzer".
    • Erzwingen Sie auf Aktionsebene zusätzlich Benutzer in der Rolle "Administrator".
  2. Sie möchten die Controller-Einschränkung auf Aktionsebene ersetzen
  3. Sie möchten die Controller-Einschränkung auf Aktionsebene entfernen und die Methode anonymen Benutzern zur Verfügung stellen

Sie haben Ihre MVC-Version nicht angegeben, daher gehe ich von der neuesten Version (MVC 4.5) aus. Dies ändert jedoch nichts an der Antwort, selbst wenn Sie MVC 3 verwenden.

[Anonymous]überschreibt den Controller [Authorize](Fall 3)

Fall 3. Ich muss mich nicht mit (der Verwendung von [AllowAnonymous]) befassen, da dies bereits in SO und im gesamten Web beantwortet wurde . Es genügt zu sagen: Wenn Sie [AllowAnonymous]eine Aktion angeben , wird diese Aktion auch dann öffentlich, wenn der Controller [Authorize]sie aktiviert hat .

Sie können auch eine gesamte Website mithilfe eines globalen Filters autorisieren und AllowAnonymousfür die wenigen Aktionen oder Controller verwenden, die Sie veröffentlichen möchten.

[Authorize] ist additiv (Fall 1)

Fall 1 ist einfach. Nehmen Sie als Beispiel den folgenden Controller:

[Authorize(Roles="user")]
public class HomeController : Controller {
    public ActionResult AllUsersIndex() {
        return View();
    }

    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
}

Standardmäßig sind [Authorize(Roles="user")]alle Aktionen im Controller nur für Konten in der Rolle "Benutzer" verfügbar. Für den Zugriff AllUsersIndexmüssen Sie sich daher in der Rolle "Benutzer" befinden. Für den Zugriff AdminUsersIndexmüssen Sie sich jedoch sowohl in der Rolle "Benutzer" als auch in der Rolle "Administrator" befinden. Zum Beispiel:

  • Benutzername: Bob, Rollen: Benutzer, kann nicht zugreifen AdminUsersIndex, kann aber zugreifenAllUsersIndex
  • Benutzername: Jane, Rollen: admin, kann nicht auf AdminUsersIndexoder zugreifenAllUsersIndex
  • Benutzername: Tim, Rollen: Benutzer & Administrator, kann auf AdminUsersIndexund zugreifenAllUsersIndex

Dies zeigt, dass das [Authorize]Attribut additiv ist. Dies gilt auch für die UsersEigenschaft des Attributs, die kombiniert werden kann Roles, um es noch restriktiver zu machen.

Dieses Verhalten ist auf die Funktionsweise der Controller- und Aktionsattribute zurückzuführen. Die Attribute werden miteinander verkettet und in der Auftragssteuerung dann Aktion angewendet. Wenn der erste die Autorisierung verweigert, wird die Steuerung zurückgegeben und das Attribut der Aktion wird nicht aufgerufen. Wenn der erste die Autorisierung besteht, wird auch der zweite geprüft. Sie können diese Reihenfolge überschreiben, indem Sie Order(zum Beispiel [Authorize(Roles = "user", Order = 2)]) angeben .

Überschreiben [Authorize](Fall 2)

Fall 2 ist schwieriger. Erinnern Sie sich von oben daran, dass die [Authorize]Attribute in der Reihenfolge (Global dann) Controller und dann Aktion untersucht werden. Der erste, der feststellt, dass der Benutzer nicht zur Autorisierung berechtigt ist, gewinnt, die anderen werden nicht angerufen.

Eine Möglichkeit, dies zu umgehen, besteht darin, zwei neue Attribute wie folgt zu definieren. Das [OverrideAuthorize]tut nichts anderes als aufzuschieben [Authorize]; Der einzige Zweck besteht darin, einen Typ zu definieren, nach dem wir suchen können. Damit [DefaultAuthorize]können wir überprüfen, ob die in der Anfrage aufgerufene Aktion mit einem gekennzeichnet ist [OverrideAuthorize]. Wenn dies der Fall ist, verschieben wir die Überprüfung der Aktionsautorisierung, andernfalls fahren wir mit der Überprüfung der Controller-Ebene fort.

public class DefaultAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var action = filterContext.ActionDescriptor;
        if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;

        base.OnAuthorization(filterContext);
    }
}
public class OverrideAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
    }
}

Wir können es dann so verwenden:

[DefaultAuthorize(Roles="user")]
public class HomeController : Controller {
    // Available to accounts in the "user" role
    public ActionResult AllUsersIndex() {
        return View();
    }
    // Available only to accounts both in the "user" and "admin" role
    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
    // Available to accounts in the "superuser" role even if not in "user" role
    [OverrideAuthorize(Roles = "superuser")]
    public ActionResult SuperusersIndex() {
        return View();
    }
}

Im obigen Beispiel SuperusersIndexsteht ein Konto mit der Rolle "Superuser" zur Verfügung, auch wenn es nicht die Rolle "Benutzer" hat.

Andy Brown
quelle
Bei mir gibt es keinen Unterschied. Es gibt einen Attributbereich. Die Genehmigung sollte auf den ersten Damm verschoben werden. Dies entspricht der Vergleichslogik, if(condition1&&condition2) wenn die erste Bedingung falsch ist, der Compailer nicht nach der zweiten Bedingung sucht und den if-Block überspringt.
AliRıza Adıyahşi
Vielen Dank für die sehr detaillierten Informationen. Dies möchte ich erfahren, als ich diese Frage stellte. Vielen Dank!
Frank
Haben "Benutzer" -Rollen Zugriff auf die SuperusersIndexAktionsmethode?
Ashkan
1
Nein. Das OverrideAuthorizeersetzt vollständig die Standardberechtigungen, die durch DefaultAuthorizeden if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;inDefaultAuthorizeAttribute.OnAuthorization
Andy Brown
4
In MVC5 kann Fall 2 einfach durch Hinzufügen des [OverrideAuthorization]Attributs zur Aktion ausgeführt werden, wie in dieser Antwort beschrieben .
Bpainter
44

Ich möchte Overriding [Authorize] etwas hinzufügen (Fall 2)

OverrideAuthorizeAttribute und DefaultAuthorizeAttribute funktionieren einwandfrei, aber ich stelle fest, dass Sie auch OverrideAuthorizationAttribute verwenden können, das auf einer höheren Ebene definierte Berechtigungsfilter überschreibt.

[Authorize(Roles="user")]
public class HomeController : Controller {
    // Available to accounts in the "user" role
    public ActionResult AllUsersIndex() {
        return View();
    }
    // Available only to accounts both in the "user" and "admin" role
    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
    // Available to accounts in the "superuser" role even if not in "user" role
    [OverrideAuthorization()]
    [Authorize(Roles = "superuser")]
    public ActionResult SuperusersIndex() {
        return View();
    }
}
Akodo_Shado
quelle
Aber das funktioniert nicht mit Custom AuthorizeAttribute, oder?
David Liang
2
Benötigt MVC 5.
Chuck Kasabula
Es hat mir geholfen. Aber bitte fügen Sie hinzu, dass es MVC5 in der Antwort ist, falls die Leute das verpassen.
Craig Brett
2

Ich habe den zweiten Fall dieser Antwort für ASP.NET Core 2.1 angepasst.

Der Unterschied zu ASP.NET Core AuthorizeAttributebesteht darin, dass Sie die AuthorizeAttribute.OnAuthorizationBasismethode nicht aufrufen müssen , um zur normalen Autorisierung zu gelangen. Dies bedeutet, dass selbst wenn Sie die Basismethode nicht explizit aufrufen, die Basis AuthorizeAttributedie Autorisierung kurzschließen kann, indem der Zugriff verboten wird.

Was ich getan habe ist, dass ich eine erstellt habe DefaultAuthorizeAttribute, die nicht von AuthorizeAttribute, sondern von erbt Attribute. Da das DefaultAuthorizeAttributenicht erbt von AuthorizeAttribute, musste ich das Autorisierungsverhalten neu erstellen.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class DefaultAuthorizeAttribute : Attribute, IAuthorizationFilter
{
    private readonly AuthorizeFilter m_authorizeFilter;

    public DefaultAuthorizeAttribute(params string[] authenticationSchemes)
    {
        var policyBuilder = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(authenticationSchemes)
            .RequireAuthenticatedUser();
        m_authorizeFilter = new AuthorizeFilter(policyBuilder.Build());
    }

    public void OnAuthorization(AuthorizationFilterContext filterContext)
    {
        if (filterContext.ActionDescriptor is ControllerActionDescriptor controllerAction
            && controllerAction.MethodInfo.GetCustomAttributes(typeof(OverrideAuthorizeAttribute), true).Any())
        {
            return;
        }
        m_authorizeFilter.OnAuthorizationAsync(filterContext).Wait();
    }
}

public class OverrideAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext filterContext) { }
}
Jo Ham
quelle
Das funktioniert nicht. Schauen Sie sich die Implementierung von an OnAuthorizationAsync- es wird GetEffectivePolicyAsyncimmer null zurückgegeben, da dies GetEffectivePolicyAsyncnur mit Filtern funktioniert, die tatsächlich auf den Controller / die Aktion angewendet werden, was unser Autorisierungsfilter nicht ist. Wir behalten es nur in m_authorizeFilter...
Jan Palas
1

Wenn Sie es dann auf dem Controller verwenden, werden alle Methoden dieses Controllers ausgeführt.

[Authorize]
public class SomeController(){

    // all actions are effected
    public ActionResult Action1
    public ActionResult Action2

Wenn Sie eine dieser Aktionen verhindern möchten, können Sie Folgendes verwenden:

[Authorize]
public class SomeController(){

    // all actions are effected
    public ActionResult Action1
    public ActionResult Action2

    [AllowAnonymous]
    public ActionResult Action3 // only this method is not effected...
AliRıza Adıyahşi
quelle
1
Das OP fragte, was passiert, wenn Sie [Authorize]sowohl den Controller als auch die Aktion " Welches wird den Effekt haben? Beide? " Anlegen. Sie haben darauf nicht geantwortet.
Andy Brown
@Andy Brown, also, wenn er es auf dem Controller definiert, muss es nicht auf eine Aktion dieses Controllers geschrieben werden. Es ist nicht erforderlich, es für eine Aktion zu verwenden. Sie können aus meiner Antwort verstehen. Ich meine, das muss ich auch nicht erklären.
AliRıza Adıyahşi
2
Ich denke, wenn Sie die Antwort klar lesen, hat er sie beantwortet. Da er sagt, dass alle Methoden betroffen sein werden, bedeutet dies, dass es keine Rolle spielt, ob Sie es auch auf eine Aktion setzen.
Nick N.
1
@ NickN. Mein Punkt ist, dass es wichtig sein kann . AuthorizeAttribute Kette zusammen. Wenn der erste den Benutzer zulässt, kann der zweite den Benutzer weiterhin blockieren. Die Frage betrifft auch zwei AuthorizeAttribute (eines auf dem Controller, eines auf der Aktion), nicht Authorizedann AllowAnonymous. Ich habe eine weitere Antwort hinzugefügt, um meinen Standpunkt zu veranschaulichen.
Andy Brown
@AndyBrown Ich stimme dir zu, jetzt habe ich deine Antwort gesehen.
Nick N.