.net asp.net-mvc authentication forms-authentication asp.net-routing

Cómo redirigir a una URL de inicio de sesión dinámica en ASP.NET MVC



asp.net-mvc authentication (3)

Estoy creando un sitio web multi-tenancy que aloja páginas para clientes. El primer segmento de la URL será una cadena que identifica al cliente, definido en Global.asax utilizando el siguiente esquema de enrutamiento de URL:

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

Esto funciona bien, con URLs como / foo / Home / Index.

Sin embargo, cuando se utiliza el atributo [Autorizar], quiero redireccionar a una página de inicio de sesión que también usa el mismo esquema de mapeo. Entonces, si el cliente es foo, la página de inicio de sesión sería / foo / Account / Login en lugar de la redirección fija / Account / Login definida en web.config.

MVC usa un HttpUnauthorizedResult para devolver un estado 401 no autorizado, lo que presumo hace que ASP.NET redirija a la página definida en web.config.

Entonces, ¿alguien sabe cómo anular el comportamiento de redirección de inicio de sesión de ASP.NET? ¿O sería mejor redirigir en MVC creando un atributo de autorización personalizado?

EDITAR - Respuesta: después de investigar en el origen de .Net, decidí que un atributo de autenticación personalizado es la mejor solución:

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 } }); } } }


Creo que el problema principal es que si vas a utilizar la clase de Autenticación de Forms ASP.NET incorporada (y no hay una buena razón por la que no deberías), algo al final del día va a llamar a FormsAuthentication.RedirectToLoginPage() que va a mirar la URL configurada. Solo hay una URL de inicio de sesión, y así es como lo diseñaron.

Mi intento de resolver el problema (posiblemente una implementación de Rube Goldberg) sería permitir que se redirija a una sola página de inicio de sesión en la raíz compartida por todos los clientes, por ejemplo / cuenta / inicio de sesión. Esta página de inicio de sesión no mostraría nada en realidad; inspecciona el parámetro ReturnUrl o algún valor que tengo en la sesión o una cookie que identifica al cliente y lo usa para emitir un redireccionamiento 302 inmediato a la página específica / cliente / cuenta / inicio de sesión. Es una redirección extra, pero probablemente no se note y te permite usar los mecanismos de redirección integrados.

La otra opción es crear su propio atributo personalizado tal como lo describe y evitar todo lo que llame al método RedirectToLoginPage() en la clase FormsAuthentication , ya que lo reemplazará con su propia lógica de redireccionamiento. (Puede crear su propia clase que sea similar.) Como es una clase estática, no conozco ningún mecanismo por el que pueda simplemente inyectar su propia interfaz alternativa y hacer que funcione mágicamente con el atributo [Autorizar] existente, que golpes, pero la gente ha hecho cosas similares antes .

¡Espero que ayude!


En la versión RTM de ASP.NET MVC, falta la propiedad Cancelar. Este código funciona con 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 } }); } } } }

Editar: es posible que desee deshabilitar la autenticación de formularios predeterminada loginUrl en web.config, en caso de que alguien olvide que tiene un atributo personalizado y utiliza el atributo [Autorizar] incorporado por error.

Modifique el valor en web.config:

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

Luego crea un método de acción ''ERROR'' que registra un error y redirige al usuario a la página de inicio de sesión más genérica que tengas.


Mi solución a este problema fue una clase ActionResult personalizada:

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