8

Im Wesentlichen möchte ich eine freundliche Nachricht zeigen, wenn jemand nicht Teil einer Rolle in meinem Attribut aufgeführt ist. Momentan spuckt meine Anwendung den Benutzer nur auf den Anmeldebildschirm zurück. Ich habe ein paar Posts gelesen, in denen es darum geht, ein benutzerdefiniertes Attribut zu erstellen, das [AuthorizeAttribute] erweitert, aber ich denke, da muss etwas aus der Box sein, um das zu tun?Attribut für .net MVC Controller Aktionsmethode

Kann mir bitte jemand in die richtige Richtung zeigen, wo ich suchen muss, um den Benutzer nicht zum Anmeldeformular zu schicken, sondern einfach eine "nicht autorisierte" Nachricht zu erschießen?

Antwort

2

Wenn Einfachheit oder die totale Kontrolle über die Logik ist, was Sie möchten, können Sie diese Methode in Aktion rufen:

User.IsInRole("NameOfRole"); 

Es gibt einen bool und Sie können den Rest der Logik tun abhängig von diesem Ergebnis.

Ein anderes, das ich in einigen Fällen verwendet habe, ist:

System.Web.Security.Roles.GetRolesForUser(); 

Ich denke, dass eine Zeichenfolge [] gibt aber zitieren Sie mich nicht daran.

EDIT: Ein Beispiel hilft immer ...

public ActionResult AddUser() 
{ 
    if(User.IsInRoles("SuperUser") 
    { 
     return View("AddUser"); 
    } 
    else 
    { 
     return View("SorryWrongRole"); 
    } 
} 

Solange Ihr Rückgabetyp ist "Action" Sie irgendeine der akzeptierten Rückgabetypen zurückkehren konnte (Viewresult, PartialViewResult, RedirectResult, JsonResult ...)

+0

also diese Logik verwenden, müsste ich Teilansichten mit "freundliche Nachrichten" korrigieren? Ist es nicht möglich, die gesamte Aktionsmethode mit einem Attribut zu kombinieren, das dasselbe tut? – Kyle

+0

Ich habe oben ein Beispiel hinzugefügt. Ihre andere Möglichkeit besteht natürlich darin, Ihr eigenes Attribut zu schreiben, wie Sie es genannt haben (das wäre zwar der sauberste, aber härtere Unit-Test), aber das ist definitiv kein Out-of-the-Box-Ansatz. –

0

Das out-of-the-box-Verhalten ist, dass das [Authorize] -Attribut ein HTTP 401 zurückgibt. Das FormsAuthenticationModule (das standardmäßig geladen wird) fängt dieses 401 ab und leitet den Benutzer zur Anmeldeseite um. Sehen Sie sich System.Web.Security.FormsAuthenticationModule :: OnLeave in Reflector an, um zu sehen, was ich meine.

Wenn Sie möchten, dass das AuthorizeAttribute etwas anderes tut, als das HTTP 401 zurückgibt, müssen Sie die AuthorizeAttribute :: HandleUnauthorizedRequest-Methode überschreiben und Ihre benutzerdefinierte Logik dort implementieren. Alternativ nur diesen Teil \ Web.config von ~ ändern:

<forms loginUrl="~/Account/LogOn" timeout="2880" /> 

Und es auf eine andere URL verweisen machen, wie ~/AccessDenied.

3

Ich bin vor ein paar Tagen in dieses Problem geraten und die Lösung ist ein bisschen detailliert, aber hier sind die wichtigen Bits. In AuthorizeAttribute gibt die Methode OnAuthorization eine HttpUnauthorizedResult zurück, wenn die Autorisierung fehlschlägt, was die Rückgabe eines benutzerdefinierten Ergebnisses ein wenig schwierig macht.

Was ich getan habe, war, eine CustomAuthorizeAttribute-Klasse zu erstellen und die OnAuthorization-Methode zu überschreiben, um stattdessen eine Ausnahme auszulösen. Ich kann dann diese Ausnahme mit einer benutzerdefinierten Fehlerbehandlungsroutine abfangen und eine angepasste Fehlerseite anzeigen, anstatt eine 401 (nicht autorisiert) zurückzugeben.

<customErrors mode="On" defaultRedirect="~/Error"> 
     <error statusCode="401" redirect="~/Error/Unauthorized" /> 
     <error statusCode="404" redirect="~/Error/NotFound" /> 
    </customErrors> 

und dann implementieren Sie Ihre eigene Errorcontroller zu dienen benutzerdefinierte Seiten:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) { 
     if (filterContext == null) { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (AuthorizeCore(filterContext.HttpContext)) { 
      HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
      cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
      cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
     } 
     else { 
      // auth failed, redirect to login page 
      // filterContext.Result = new HttpUnauthorizedResult(); 

      throw new HttpException ((int)HttpStatusCode.Unauthorized, "Unauthorized");     
     } 
    } 
} 

dann in Ihrer web.config können Sie benutzerdefinierte Handler für bestimmte Fehler gesetzt.

Auf IIS7 müssen Sie in die Einstellung Response.TrySkipIisCustomErrors = true; suchen, um Ihre benutzerdefinierten Fehler zu aktivieren.

6

Ich könnte etwas zu spät kommen, wenn ich $ 0,02 hinzufüge, aber wenn Sie Ihren CustomAuthorizationAttribue erstellen, können Sie die AuthorizationContext.Result property diktieren, wo die AuthorizeAttribute.HandleUnauthorizedRequest -Methode den Benutzer leitet.

Hier ist ein sehr einfaches Beispiel, das Sie die URL angeben kann, wo ein Benutzer soll nach gescheiterten Genehmigung gesendet werden:

public class Authorize2Attribute : AuthorizeAttribute 
{ 
    // Properties 

    public String RedirectResultUrl { get; set; } 

    // Constructors 

    public Authorize2Attribute() 
     : base() 
    { 
    } 

    // Overrides 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (String.IsNullOrEmpty(RedirectResultUrl)) 
      base.HandleUnauthorizedRequest(filterContext); 

     else 
      filterContext.Result = new RedirectResult(RedirectResultUrl); 
    } 
} 

Und wenn ich den Benutzer/Error/Unerlaubte wie vorgeschlagen umleiten wollte in einem frühen Beitrag:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")] 
public ActionResult RestrictedAction() 
{ 
    // TODO: ... 
} 
+0

Ich habe eine ähnliche Sache gemacht, aber ich überprüfe, ob der Benutzer authentifiziert ist. Dadurch kann ich Benutzer ablehnen, weil sie nicht in einer Rolle sind, aber sie werden nicht aufgefordert, sich anzumelden –

2

Sehr ähnlich crazyarabian, aber ich nur in meinem String umleiten, wenn der Benutzer tatsächlich authentifiziert ist. Dadurch kann das Attribut auf die Standardanmeldeseite umgeleitet werden, wenn es derzeit nicht angemeldet ist, aber auf eine andere Seite, wenn es keine Berechtigungen für den Zugriff auf die URL hat.