it-swarm.com.de

So leiten Sie in ASP.NET MVC zu einer dynamischen Anmelde-URL um

Ich erstelle eine mandantenfähige Website, die Seiten für Kunden hostet. Das erste Segment der URL ist eine Zeichenfolge, die den in Global.asax definierten Client anhand des folgenden URL-Routing-Schemas identifiziert:

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

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

Bei Verwendung des Attributs [Authorize] möchte ich jedoch auf eine Anmeldeseite umleiten, die dasselbe Mapping-Schema 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 HttpUnauthorizedResult, um einen nicht autorisierten 401-Status zurückzugeben. Dies führt vermutlich dazu, dass ASP.NET zu der in web.config definierten Seite umgeleitet wird.

Weiß jemand, wie das ASP.NET-Anmeldungsumleitungsverhalten überschrieben werden kann? Oder wäre es besser, in MVC umzuleiten, indem Sie ein benutzerdefiniertes Berechtigungsattribut erstellen?

EDIT - Antwort: Nach einigen Eingriffen in die .Net-Quelle entschied ich, dass ein benutzerdefiniertes Authentifizierungsattribut die beste Lösung ist:

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 }
                });
        }
    }
}
92
Mike Scott

Ich denke, das Hauptproblem ist, dass, wenn Sie die eingebaute ASP.NET FormsAuthentication-Klasse verwenden (und es keinen guten Grund gibt, dass Sie dies nicht tun sollten), etwas am Ende des Tages FormsAuthentication.RedirectToLoginPage() heißt Gehen Sie auf die eine konfigurierte URL. Es gibt immer nur eine Login-URL, und so haben sie es entworfen.

Ich könnte das Problem (möglicherweise eine Rube Goldberg-Implementierung) erst einmal auf eine einzige Anmeldeseite im Stammverzeichnis weiterleiten, die von allen Clients gemeinsam genutzt wird, z. B./account/login. Diese Anmeldeseite würde eigentlich nichts anzeigen. Es prüft entweder den ReturnUrl-Parameter oder einen Wert, den ich in der Sitzung erhalten habe, oder ein Cookie, das den Client identifiziert, und verwendet diesen, um eine sofortige Weiterleitung an die spezifische/client/account/login-Seite auszugeben. Es ist eine zusätzliche Umleitung, die aber wahrscheinlich nicht wahrnehmbar ist, und Sie können die integrierten Umleitungsmechanismen verwenden.

Die andere Option besteht darin, während der Beschreibung Ihr eigenes benutzerdefiniertes Attribut zu erstellen und alles zu vermeiden, das die RedirectToLoginPage()-Methode für die FormsAuthentication-Klasse aufruft, da Sie es durch Ihre eigene Umleitungslogik ersetzen. (Möglicherweise erstellen Sie eine eigene ähnliche Klasse.) Da es sich um eine statische Klasse handelt, ist mir kein Mechanismus bekannt, durch den Sie einfach Ihr eigenes alternatives Interface einfügen und es magisch mit dem vorhandenen [Authorize] -Attribut arbeiten lassen Schläge, aber Leute haben ähnliche Dinge schon gemacht .

Hoffentlich hilft das!

30

In der Version RTM 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: Möglicherweise möchten Sie die standardmäßige Formularauthentifizierung loginUrl in web.config deaktivieren. Falls jemand vergisst, haben Sie ein benutzerdefiniertes Attribut und verwenden versehentlich das integrierte Attribut [Authorize].

Ändern Sie den Wert in web.config:

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

Machen Sie dann eine Aktionsmethode "ERROR", die einen Fehler protokolliert und den Benutzer auf die allgemeinste Anmeldeseite umleitet, die Sie haben.

40
user134936

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; }
    }
2
Kieron

Wenn Sie sich jedoch für die Verwendung der integrierten ASP.NET-FormsAuthentication entscheiden, können Sie Application_AuthenticateRequest in Global.asax.cs wie folgt überschreiben:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    string url = Request.RawUrl;

    if (url.Contains(("Account/Login"))
    {
        return;
    }

    if (Context.User == null)
    {
        // Your custom tenant-aware logic
        if (url.StartsWith("/foo"))
        {
            // Your custom login page.
            Response.Redirect("/foo/Account/Login");
            Response.End();
            return;
        }
    }
}
0
turdus-merula