2011-01-07 16 views
3

Ich verwende einen benutzerdefinierten Mitgliedschaftsanbieter. Alles funktioniert super. Allerdings habe ich in meiner web.config-Datei "Benutzer verweigern" aktiviert, so dass die gesamte Website gesperrt ist.ASP.NET MVC 2 Autorisierung Problem

Das funktioniert super. Der Benutzer wird zur Anmeldeseite weitergeleitet.

Jetzt habe ich ein paar Controller/Aktionen, die ich anonymen Zugriff zulassen möchte. Über Seite, Passwort zurücksetzen, etc.

Der einzige Weg, wie ich herausfinden kann, wie dies zu tun ist, die gesamte Website zu entsperren, legen Sie [Authorize] -Attribute auf jedem Controller und entfernen Sie sie für den Controller/Aktionen, die ich anonym möchte.

Dies scheint rückwärts zu mir. Ich bevorzuge es, alles standardmäßig zu sperren und das, was anonym ist, freizuschalten.

Gibt es einen Weg um dies?

Danke!

Antwort

3

Ich kann über alternative Möglichkeiten nachdenken, dies zu implementieren, aber alle beinhalten die Verwendung eines benutzerdefinierten AuthorizeAttribute. Eine Möglichkeit, dies zu tun, wäre ein Basiscontroller, der das angepasste AuthorizeAttribute verwendet, von dem alle Controller abgeleitet sind. Dieses Attribut wird angepasst, um den anonymen (und nicht autorisierten) Zugriff auf eine Aktion zu verhindern, es sei denn, der Controller oder die Aktion selbst wurde mit einem anderen Attribut versehen, z. B. AnonymousEnabledAttribute. Alle Ihre Controller würden von diesem Controller abgeleitet und erben damit sein Standardverhalten "kein anonymes Standardverhalten". Sie würden dann einfach die Controller/Aktionen dekorieren, die anonym mit dem AnonymousEnabledAttribute sein sollen - die Überschreibung für diesen Controller oder diese Aktion bereitstellen. Oder, für einen Controller, erben Sie einfach nicht vom geschützten Controller und alle seine Aktionen werden öffentlich.

Oh, und Ihre ganze Website müsste offen bleiben.

[OverridableAuthorize] 
public abstract class ProtectedController : Controller 
{ 
} 

public class MostlyProtectedController : ProtectedController 
{ 
    public ActionResult ProtectedAction() 
    { 
    } 

    [AnonymousEnabled] 
    public ActionResult PublicAction() 
    { 
    } 
} 

[AnonymousEnabled] 
public class ExplicitlyPublicController : ProtectedController 
{ 
    // inherits additional behaviors, but anonymous is enabled by attribute 
} 

public class PublicByOmissionController : Controller 
{ 
    // doesn't inherit and is thus public -- assuming whole site is open 
} 

public class AnonymousEnabledAttribute : Attribute 
{ 
} 

public class OverridableAuthorizeAttribute : AuthorizeAttribute 
{ 
    public override void OnAuthorization(AuthorizationContext context) 
    { 
      context.HttpContext.Items["ActionDescriptor"] = context.ActionDescriptor; 
      base.OnAuthorize(context); 
    } 

    public override bool AuthorizeCore(HttpContextBase context) 
    { 
     var actionDescriptor = context.Items["ActionDescriptor"] as ActionDescriptor; 
     if (actionDescriptor == null) 
     { 
      throw InvalidOperationException("ActionDescriptor missing from context"); 
     } 
     var attribute = actionDescriptor 
          .GetCustomAttributes(typeof(AnonymousEnabledAttribute,true) 
          .FirstOrDefault(); 
     if (attribute == null) 
     { 
      return base.AuthorizeCore(context); 
     } 
     return true; 
    } 
} 
+0

Vielen Dank für diesen Vorschlag. Dies würde bedeuten, dass die Site (wie in der web.config) vollständig geöffnet wäre, aber alle Controller standardmäßig gesperrt wären, so lange sie vom ProtectedController erben. – cbmeeks

+0

@cbmeeks - korrekt. Außerdem denke ich, dass die Verwendung des AuthorizeAttribute (oder etwas, das davon abgeleitet ist), d. H. Der MVC-Sicherheit, definitiv dem Versuch vorzuziehen ist, WebForms-basierte Sicherheit und MVC-Sicherheit zu mischen. – tvanfosson

+0

** ACHTUNG ** Die AuthorizeAttribute-Klasse muss nach ihrer Erstellung unveränderbar sein. Sie können HttpContext.Items verwenden, um den ActionDescriptor zu speichern, aber Sie müssen ihn * absolut NICHT als Instanzfeld innerhalb der Klasse speichern. Der Grund dafür ist, dass eine einzelne Instanz von AuthorizeAttribute verwendet werden kann, um mehrere gleichzeitige Anforderungen zu verarbeiten, und durch die Einführung eines Instanzfeldes haben Sie jetzt eine Race-Bedingung in Ihrem Sicherheitscode. – Levi

1

Sie können einen Ort in der Datei web.config für die Controller erstellen, die Sie wollen immer erlauben:

<configuration> 
    <system.web> 
     ... 
     <authorization> 
      <deny users="?" /> 
     </authorization> 
    </system.web> 
    ... 
    <location path="MyArea/MyController"> 
     <system.web> 
      <authorization> 
       <allow users="*" /> 
      </authorization> 
     </system.web> 
    </location> 
    ... 
</configuration> 
+0

Danke, aber das scheint nie zu funktionieren. Ich habe dies eingefügt und es erfordert immer noch die Genehmigung zu anonymen Aktionen. – cbmeeks

+0

@cbmeeks: Ich weiß nicht was ich sagen soll. Wir verwenden diesen Ansatz und es funktioniert gut für uns. – StriplingWarrior

+1

** ACHTUNG ** Der Versuch, die -basierte Sicherheit mit MVC-Sicherheit zu kombinieren, ist ein Rezept für eine Katastrophe. -basierte Sicherheit ist für dateibasierte Ressourcen wie ASPX-Seiten gedacht. Da Controller-Klassen typenbasiert und nicht dateibasiert sind, kann die -basierte Sicherheit umgangen werden. – Levi