91

Ich erstelle eine Multi-Tenancy-Website, die Seiten für Clients hostet. Das erste Segment der URL wird eine Zeichenfolge sein, die den Client identifiziert, definiert in Global.asax die folgende URL-Routing-Schema verwendet:Umleiten zu einer dynamischen Login-URL in ASP.NET MVC

"{client}/{controller}/{action}/{id}" 

Dies funktioniert gut, mit URLs wie/foo/Home/Index.

Bei Verwendung des Attributs [Autorisieren] möchte ich jedoch zu einer Anmeldeseite umleiten, die ebenfalls dasselbe Zuordnungsschema verwendet. Wenn der Client also foo ist, lautet die Anmeldeseite/foo/Account/Login anstelle der in web.config definierten festen/Account/Login-Weiterleitung.

MVC verwendet ein HttpUnauthorizedResult, um einen nicht autorisierten 401-Status zurückzugeben, von dem ich vermute, dass ASP.NET zu der in web.config definierten Seite umgeleitet wird.

Wer weiß also, wie das ASP.NET-Login-Redirect-Verhalten überschrieben wird? Oder wäre es besser, in MVC umzuleiten, indem Sie ein benutzerdefiniertes Autorisierungsattribut erstellen?

EDIT - Antwort: nach ein paar in die Quelle .Net graben, habe ich beschlossen, dass eine benutzerdefinierte Authentifizierung Attribut ist die beste Lösung:

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

     if (filterContext.Cancel && filterContext.Result is HttpUnauthorizedResult) 
     { 
      filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary 
       { 
        { "client", filterContext.RouteData.Values[ "client" ] }, 
        { "controller", "Account" }, 
        { "action", "Login" }, 
        { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
       }); 
     } 
    } 
} 
+2

fast genau die gleiche Sache mit Routing zu tun, so brauchte ich das! Vielen Dank! –

+0

Danke, ich habe versucht, herauszufinden, wie man etwas Ähnliches macht. – Chance

+0

es gab mir eine Idee für die eigene Umsetzung, vielen Dank! –

Antwort

30

Ich denke, die wichtigste Frage, das ist, wenn du gehst Um an der integrierten ASP.NET FormsAuthentication-Klasse zu pendeln (und es gibt keinen guten Grund, warum Sie das nicht tun sollten), wird am Ende des Tages FormsAuthentication.RedirectToLoginPage() aufgerufen, die sich die eine konfigurierte URL ansehen wird. Es gibt immer nur eine Login-URL, und genau so haben sie sie entworfen.

Mein Stich auf das Problem (möglicherweise eine Rube Goldberg-Implementierung) wäre, um es zu einer einzigen Login-Seite auf dem Stamm von allen Clients geteilt teilen, sagen/Konto/Login. Diese Anmeldeseite würde eigentlich nichts anzeigen; Es überprüft entweder den ReturnUrl-Parameter oder einen Wert, den ich in der Sitzung habe, oder einen Cookie, der den Client identifiziert und diesen verwendet, um eine sofortige Weiterleitung an die spezifische/client/account/login-Seite vorzunehmen. Es ist eine zusätzliche Umleitung, aber wahrscheinlich nicht bemerkbar und Sie können die eingebauten Umleitungsmechanismen verwenden. Die andere Option besteht darin, ein eigenes benutzerdefiniertes Attribut zu erstellen, wenn Sie alles beschreiben und vermeiden, das die RedirectToLoginPage()-Methode für die Klasse FormsAuthentication aufruft, da Sie sie durch Ihre eigene Umleitungslogik ersetzen. (Sie könnten Ihre eigene Klasse erstellen, die ähnlich ist.) Da es sich um eine statische Klasse handelt, ist mir kein Mechanismus bekannt, mit dem Sie einfach Ihre eigene alternative Schnittstelle einfügen und sie magisch mit dem vorhandenen Attribut [Autorisieren] arbeiten lassen Schläge, aber people have done similar things before.

Hoffe, dass hilft!

+0

Dies ist wahrscheinlich der sicherste Ansatz. Das Erstellen eines eigenen Attributs [MyAuthorize] ist gefährlich. Wenn Ihr Build nicht überprüft, dass Personen das integrierte [Authorize] -Attribut nicht verwenden, riskieren Sie, dass Benutzer (oder Sie selbst) das falsche vergessen und verwenden –

40

In der RTM-Version von ASP.NET MVC fehlt die Cancel-Eigenschaft. Dieser Code funktioniert mit ASP.NET MVC RTM:

using System; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Mvc.Resources; 

namespace ePegasus.Web.ActionFilters 
{ 
    public class CustomAuthorize : AuthorizeAttribute 
    { 
     public override void OnAuthorization(AuthorizationContext filterContext) 
     { 
      base.OnAuthorization(filterContext); 
      if (filterContext.Result is HttpUnauthorizedResult) 
      { 
       filterContext.Result = new RedirectToRouteResult(
        new System.Web.Routing.RouteValueDictionary 
         { 
           { "langCode", filterContext.RouteData.Values[ "langCode" ] }, 
           { "controller", "Account" }, 
           { "action", "Login" }, 
           { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
         }); 
      } 
     } 
    } 
} 

Edit: Sie können das Standard-Formularauthentifizierung loginUrl in web.config deaktivieren - falls jemand vergisst Sie eine benutzerdefinierte Attribut und Verwendungen haben das eingebaute Attribut [Autorisieren] aus Versehen.

Ändern Sie den Wert im Web.config:

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

dann eine Aktion Methode ‚ERROR‘ machen, die einen Fehler meldet und leitet den Benutzer auf die allgemeinste Login-Seite haben.

+2

: Fügen Sie {word, null} zum Wörterbuch (oder was auch immer in Ihrem Gebiet) hinzu wird aufgerufen, wenn Sie MVC 2 und höher verwenden - sonst wird es von der Seite geerbt, die Sie besuchen wollten –

2

Meine Lösung für dieses Problem war eine benutzerdefinierte ActionResult Klasse:

sealed public class RequiresLoginResult : ActionResult 
    { 
     override public void ExecuteResult (ControllerContext context) 
     { 
      var response = context.HttpContext.Response; 

      var url = FormsAuthentication.LoginUrl; 
      if (!string.IsNullOrWhiteSpace (url)) 
       url += "?returnUrl=" + HttpUtility.UrlEncode (ReturnUrl); 

      response.Clear(); 
      response.StatusCode = 302; 
      response.RedirectLocation = url; 
     } 

     public RequiresLoginResult (string returnUrl = null) 
     { 
      ReturnUrl = returnUrl; 
     } 

     string ReturnUrl { get; set; } 
    } 
Verwandte Themen