2010-02-23 11 views
52

Ich habe einen Admin-Bereich und ich möchte nur Admins in den Bereich eingeben. Ich erwog, das Attribut "Autorisiert" zu jedem Controller im Admin-Bereich hinzuzufügen. Gibt es keine elegante Lösung oder ist diese Funktion nicht im Framework selbst vorhanden?Wie können wir die Berechtigung für einen ganzen Bereich in ASP.NET MVC festlegen?

EDIT: Es tut mir leid, ich sollte dies zuvor erwähnt haben. Ich verwende ein benutzerdefiniertes AuthorizedAttribute, das von AuthorizeAttribute abgeleitet wurde.

+0

Siehe meinen Blogpost [Sicherung Ihrer ASP.NET MVC 3-Anwendung] (http://blogs.msdn.com/b/rickandy/archive/2011/05/02/securing-your-asp-net-mvc- 3-application.aspx) – RickAndMSFT

+0

Siehe meinen Blog-Beitrag Sichern der ASP.NET MVC 4-App und des neuen AllowAnonymous-Attributs – RickAndMSFT

+0

Link für Ricks letzten Kommentar -> http://blogs.msdn.com/b/rickandy/archive/2012/ 03/23/securing-your-asp-net-mvc-4-app-und-the-new-allowanonymous-attribute.aspx –

Antwort

51

Web.config-basierte Sicherheit sollte fast nie in einer MVC-Anwendung verwendet werden. Der Grund dafür ist, dass mehrere URLs potenziell auf einen Controller treffen können und dass diese Prüfungen in Web.config immer etwas verpassen. Denken Sie daran - Controller sind nicht mit Bereichen verknüpft, Routen sind mit Bereichen verknüpft. Die MVC-Controller-Factory wird Controller aus dem Areas/-Ordner für Nicht-Bereich-Anfragen gerne zur Verfügung stellen, wenn es keinen Konflikt gibt.

Zum Beispiel der Standard-Projektstruktur verwenden, einen Admin-Bereich mit einem AdminDefaultController hinzufügen, können Sie diesen Controller getroffen über/Admin/AdminDefault/Index und/AdminDefault/Index.

Die einzige unterstützte Lösung besteht darin, Ihr Attribut auf eine Controller-Basisklasse zu setzen und sicherzustellen, dass jeder Controller innerhalb der Bereichsunterklassen dieser Basisklasse ist.

+0

Nun, ist das ein guter Weg, um sicher zu sein, dass ein Controller nur über eine einzige URL getroffen wird? Durch eine korrekte Planung von Routen vielleicht? –

+1

Es kann nicht sichergestellt werden, dass ein Controller nur über eine einzige URL erreichbar ist. Routen sind einfach * ein * Mechanismus für den Zugriff auf Controller; Sie sind nicht * der * Mechanismus. Aus diesem Grund müssen Sicherheitsattribute direkt auf die Controller selbst angewendet werden, nicht auf die Routen (und damit auf die Bereiche). Betrachten wir zum Beispiel die Einführung von MvcHandler.ashx in MVC 3. Dies würde direkt in das MVC-Framework eingreifen, indem * all * Routing umgangen wird. – Levi

+0

Ok ... bedeutet es, dass es neben der richtigen Verwendung von Sicherheitsattributen keine korrekte Antwort auf die Frage gibt? –

-5

.. sehr grob ich glaube, du willst so etwas?

Quick and dirty role management

[Authorize(Roles = "Admins")] 
public ActionResult Register() 
{ 
    ViewData["roleName"] = new SelectList(Roles.GetAllRoles(), "roleName"); 
    ViewData["PasswordLength"] = MembershipService.MinPasswordLength; 
    return View(); 
} 
+4

Bitte lesen Sie eine Frage ... – icesar

13

Wenn alle Ihre Admin-Code in einem Controller ist dann autorisieren auf die gesamte Klasse hinzuzufügen.

[Authorize] 
public class AdminController : Controller 
{ 
    ....... 
} 
+2

Das funktioniert gut für einen einzigen Controller. Aber wie machen wir das für ein ganzes Gebiet? – ppumkin

42

Ich habe gerade das gleiche Problem untersucht. Da es nicht möglich ist, Controller basierend auf Bereichen zu sichern, kommt eine einfachere Option in den Sinn.

Erstellen Sie eine Basiscontrollerdefinition für jeden Bereich, der Controller außer Kraft setzt, und fügen Sie die Sicherheitsanforderung hinzu. Dann müssen Sie nur sicherstellen, dass jeder Controller in dem Bereich AreaController anstelle von Controller überschreibt. Zum Beispiel:

/// <summary> 
/// Base controller for all Admin area 
/// </summary> 
[Authorize(Roles = "Admin")] 
public abstract class AdminController : Controller { } 

Es erfordert immer noch, dass Sie jeden Controller im Admin-Bereich von dieser Basis ableiten,

public class HomeController : AdminController 
{ 
    // .. actions 
} 

aber zumindest haben Sie einen einzigen Punkt, an dem Sie die Sicherheit für den Bereich definieren .

+2

Ja, das hört sich nach einer guten Idee an. Außerdem schlägt MSDN ähnliche Lösungen für andere Probleme vor. Vererbung ist gut. Ich mag diese Antwort. – ppumkin

+1

Ich verstehe wirklich nicht, warum Sie jeden Controller im Admin-Bereich unterklassieren sollten, anstatt einfach Ihr 1-Zeilen-Attribut über die Klassendefinition zu schreiben. – Gudradain

+4

Die einfache Antwort lautet DRY - http://en.wikipedia.org/wiki/Don't_repeat_yourself - ich kann ändern, welche Rollen in einer Codezeile geschützt sind, anstatt nach jedem [Authorize] Attribut zu suchen – Quango

13

Ich habe gerade angefangen ... aber bis jetzt funktioniert das ziemlich gut für mich.

Ich erstelle eine benutzerdefinierte AuthorizeAttribute-Klasse und füge dies in der Funktion RegisterGlobalFilters hinzu.

In CustomAuthorizeAttribute überprüfe ich verschiedene Bedingungen basierend auf dem Bereich, in dem es sich befindet.

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new CustomAuthorizeAttribute()); 
     filters.Add(new HandleErrorAttribute()); 
    } 
} 

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var routeData = httpContext.Request.RequestContext.RouteData; 
     var controller = routeData.GetRequiredString("controller"); 
     var action = routeData.GetRequiredString("action"); 
     var area = routeData.DataTokens["area"]; 
     var user = httpContext.User; 
     if (area != null && area.ToString() == "Customer") 
     { 
      if (!user.Identity.IsAuthenticated) 
       return false; 
     } 
     else if (area != null && area.ToString() == "Admin") 
     { 
      if (!user.Identity.IsAuthenticated) 
       return false; 
      if (!user.IsInRole("Admin")) 
       return false; 
     } 
     return true; 
    } 
} 
+0

danke. Das ist ein guter Weg und Nutzen. –

0

Die derzeit akzeptierte Antwort ist nicht die sicherste Lösung, weil es den Entwickler zu erfordert immer daran erinnern, dass neue Basisklasse für alle neuen Controller oder Aktionen („schwarze Liste“ zu erben, so dass Anwender alles zugreifen, es sei denn Eine Aktion ist manuell eingeschränkt). Dies verursacht insbesondere Probleme, wenn neue Entwickler, die mit Ihren Ritualen nicht vertraut sind, in das Projekt eingeführt werden. Es ist leicht zu vergessen, die richtige Controller-Klasse zu erben, wenn Sie so vorgehen, besonders nachdem Sie Ihre Augen für Wochen, Monate oder Jahre vom Projekt genommen haben. Wenn ein Entwickler vergisst zu erben, ist es nicht offensichtlich, dass im Projekt eine Sicherheitslücke besteht.

Eine sicherere Lösung für dieses Problem ist, den Zugriff auf alle Anfragen zu verweigern, dann jede Aktion mit den Rollen dekorieren, die Zugriff auf die Aktionen ("Whitelisting"; verhindert den Zugriff auf alle Benutzer, sofern manuell erlaubt). Wenn nun ein Entwickler vergisst, die richtige Autorisierung auf die weiße Liste zu setzen, werden die Benutzer Sie darüber informieren, und es ist so einfach, sich auf andere Controller zu konzentrieren, um daran zu erinnern, wie man richtigen Zugriff gewährt. Zumindest gibt es keine größere Sicherheitslücke.

In App_Start/FilterConfig.cs Datei, die FilterConfig Klasse ändern:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     ... 

     //Deny access to all controllers and actions so that only logged in Administrators can access them by default 
     filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" }); 
    } 

Dies macht alle Aktionen unzugänglich, wenn der Benutzer als Administrator angemeldet ist. Dann sollten Sie für jede Aktion, auf die ein anderer autorisierter Benutzer Zugriff haben soll, diese einfach mit [OverrideAuthorization] und [Authorize] dekorieren.

In Ihrer Geschäftslogik können Sie das Autorize-Attribut auf verschiedene Arten verwenden, ohne dass Sie befürchten müssen, dass nicht autorisierte Benutzer auf Funktionen zugreifen können. Unten sind einige Beispiele.

Beispiel 1 - Nur eingeloggte Administrator- und Dispatcher-Benutzer können auf die Methoden Index() Get und Post zugreifen.

public class MarkupCalculatorController : Controller //Just continue using the default Controller class. 
{ 
    // GET: MarkupCalculator 
    [OverrideAuthorization] 
    [Authorize(Roles = "Administrator,Dispatcher")] 
    public ActionResult Index() 
    { 
     //Business logic here. 

     return View(...); 
    } 

    // POST: DeliveryFeeCalculator 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    [OverrideAuthorization] 
    [Authorize(Roles = "Administrator,Dispatcher")] 
    public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM) 
    { 
     //Business logic here. 

     return View(...); 
    } 
} 

Beispiel 2 - Nur authentifizierte Benutzer werden die Index() Methode der Heimsteuerung zugreifen dürfen.

public class HomeController : Controller 
{ 
    [OverrideAuthorization] 
    [Authorize] //Allow all authorized (logged in) users to use this action 
    public ActionResult Index() 
    { 
     return View(); 
    } 

} 

Beispiel 3 - Nicht authentifizierte Benutzer (d.h. anonyme Benutzer) kann unter Verwendung des [AllowAnonymous] Attribut Zugriffsverfahren gestattet werden. Dies überschreibt auch automatisch den globalen Filter, ohne das Attribut [OverrideAuthorization] zu benötigen.

// GET: /Account/Login 
    [AllowAnonymous] 
    public ActionResult Login(string returnUrl) 
    { 
     ViewBag.ReturnUrl = returnUrl; 
     return View(); 
    } 

    // 
    // POST: /Account/Login 
    [HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
    { 
     ... 
    } 

Beispiel 4 - Nur Administratoren haben Zugriff auf Methoden, die die [Authorize] Attribut fehlt erlaubt sein.

public class LocationsController : Controller 
{ 

    // GET: Locations 
    public ActionResult Index() 
    { 
     //Business logic here. 
     return View(...); 
    } 
} 

Einige Anmerkungen.

Sie müssen das Attribut [OverrideAuthorization] verwenden, wenn Sie den Zugriff auf eine bestimmte Aktion auf bestimmte Rollen beschränken möchten. Andernfalls werden die Attributeigenschaften [Authorize] ignoriert und nur die Standardrolle (Administrator in meinem Beispiel) wird zugelassen, auch wenn Sie andere Rollen angeben (z. B. Dispatcher usw.).) wegen des globalen Filters. Unbefugte Benutzer werden zum Anmeldebildschirm weitergeleitet.

Das Attribut [OverrideAuthorization] bewirkt, dass die Aktion den von Ihnen festgelegten globalen Filter ignoriert. Daher müssen Sie das Attribut [Authorize] erneut anwenden, wenn Sie die Überschreibung verwenden, damit die Aktion sicher bleibt.

In Bezug auf ganze Gebiete und Controller

von Bereichen zu beschränken, wie Sie auf dem Controller anstelle der einzelnen Aktionen, die [OverrideAuthorization] und [Authorize] Attribute fragen, setzen.

Verwandte Themen