Jak przekierować na dynamiczny adres URL logowania w ASP.NET MVC

Tworzę wielotematyczną stronę internetową, która hostuje strony dla klientów. Pierwszy segment adresu URL będzie ciągiem identyfikującym klienta, zdefiniowanym w globalnym.asax przy użyciu następującego schematu trasowania adresów URL:

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

To działa dobrze, z adresami URL, takimi jak / foo / Home / Index.

Jednak przy użyciu atrybutu [Authorize] chcę przekierować do strony logowania, która również używa tego samego schematu mapowania. Więc jeśli klient jest foo, strona logowania będzie /foo / Account / Login zamiast przekierowanie stałe/konto / Logowanie zdefiniowane w web.config.

MVC używa HttpUnauthorizedResult, aby zwrócić nieautoryzowany status 401, co jak przypuszczam powoduje ASP.NET aby przekierować na stronę zdefiniowaną w web.config.

Więc czy ktoś wie, jak obejść ASP.NET logowanie przekierowanie zachowanie? A może lepiej przekierować w MVC, tworząc Niestandardowy atrybut autoryzacji?

EDIT-Answer: po pewnym kopaniu w źródle. Net zdecydowałem, że atrybut uwierzytelniania niestandardowego jest najlepszym rozwiązaniem:

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 }
                });
        }
    }
}
Author: abatishchev, 2008-12-10

3 answers

Myślę, że głównym problemem jest to, że jeśli masz zamiar piggyback na wbudowanym ASP.NET FormsAuthentication class( i nie ma dobrego powodu, aby nie powinien), coś na koniec dnia będzie wywoływać FormsAuthentication.RedirectToLoginPage(), który będzie patrzeć na jeden skonfigurowany URL. Jest tylko jeden adres URL logowania, i tak go zaprojektowali.

Moim problemem (prawdopodobnie implementacja Rube Goldberga) byłoby przekierowanie do pojedynczej strony logowania w korzeniu współdzielonym przez wszystkich klienci, powiedzmy / konto / login. Ta strona logowania nie wyświetla niczego; sprawdza albo parametr ReturnUrl, albo jakąś wartość, którą mam w sesji, albo plik cookie, który identyfikuje klienta i używa go do natychmiastowego przekierowania 302 na konkretną stronę/klient/konto / Logowanie. Jest to dodatkowe przekierowanie, ale prawdopodobnie nie zauważalne i pozwala korzystać z wbudowanych mechanizmów przekierowywania.

Inną opcją jest utworzenie własnego atrybutu niestandardowego zgodnie z opisem i uniknięcie wszystko, co wywoła metodę RedirectToLoginPage() na klasie FormsAuthentication, ponieważ zastąpisz ją własną logiką przekierowania. (Możesz utworzyć własną klasę, która jest podobna.) Ponieważ jest to klasa statyczna, nie jestem świadomy żadnego mechanizmu, za pomocą którego można by po prostu wprowadzić swój własny alternatywny interfejs i sprawić, by magicznie działał z istniejącym atrybutem [Authorize], który wieje, ale ludzie robili podobne rzeczy wcześniej .

Mam nadzieję, że to pomoże!
 30
Author: Nicholas Piasecki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-11 06:16:22

W wersji RTM ASP.NET MVC, brakuje właściwości anulowania. Ten kod działa z 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: możesz wyłączyć domyślne uwierzytelnianie formularzy loginUrl w sieci.config-w przypadku, gdy ktoś zapomni, że masz niestandardowy atrybut i użyje wbudowanego atrybutu [Authorize] przez pomyłkę.

Zmodyfikuj wartość w web.config:

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

Następnie wykonaj metodę akcji 'ERROR', która rejestruje błąd i przekierowuje użytkownika do najbardziej ogólna strona logowania, którą posiadasz.

 40
Author: user134936,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-11 02:17:31

Moim rozwiązaniem tego problemu była niestandardowa ActionResult klasa:

    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
Author: Kieron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-16 15:35:26