jquery - Una acción del controlador que devuelve una vista parcial inserta la página de inicio de sesión cuando falla la autorización
asp.net-mvc partial-views (2)
Solución 1, respuesta de respuesta que indica error
Pro ASP.NET MVC 2 Framework ofrece una solución para esto
Si se deniega la autorización de una solicitud Ajax, generalmente no desea devolver una redirección HTTP a la página de inicio de sesión, porque el código del lado del cliente no espera eso y puede hacer algo no deseado, como inyectar toda la página de inicio de sesión en el medio de cualquier página en la que esté el usuario. En su lugar, querrá enviar una señal más útil al código del lado del cliente, quizás en formato JSON, para explicar que la solicitud no fue autorizada. Puede implementar esto de la siguiente manera:
public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAjaxRequest()) {
UrlHelper urlHelper = new UrlHelper(context.RequestContext);
context.Result = new JsonResult {
Data = new {
Error = "NotAuthorized",
LogOnUrl = urlHelper.Action("LogOn", "Account")
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
base.HandleUnauthorizedRequest(context);
}
}
A continuación, obtendría un objeto JSON del controlador {''Error'': ''NotAuthorized'', ''LogonUrl'': ''...''}
que luego podría utilizar para redirigir al usuario.
Y una respuesta alternativa, si está esperando HTML, podría ser devolver una cadena simple, como NotAuthorized:<your_url>
y verificar si la respuesta coincide con este patrón.
Solución 2, devolución y manejo 401 Unautorized
estado no 401 Unautorized
Como esto tiene que verificarse en la devolución de llamada success
cada solicitud ajax, esto se vuelve bastante tedioso. Sería bueno poder atrapar este caso globalmente. La mejor solución sería devolver un código de estado 401 Unauthorized
del servidor y usar .ajaxError
de jQuery para capturarlo, pero esto es problemático en IIS / ASP.NET, ya que es un compromiso mortal redirigirlo a la página de inicio de sesión si la respuesta ha este código de estado Siempre que la etiqueta <authentication>
esté presente en web.config
esta redirección ocurrirá [1] si no hace algo al respecto.
Así que hagamos algo al respecto. This forma hacky parecía agradable. En su global.asax.cs
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 && Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
(Me encantaría saber si alguien sabe de algún método mejor para devolver un código de estado 401
).
Al hacer esto, impide el comportamiento predeterminado de redirigir a la página de inicio de sesión cuando la solicitud es una solicitud AJAX. Por lo tanto, puede usar el AuthorizeAttribute
predeterminado tal como es, ya que Application_EndRequest
se ocupa del resto.
Ahora, en el código jQuery usaremos la función .ajaxError
para detectar el error. Este es un controlador de eventos ajax global, lo que significa que interceptará todos los errores cometidos por cualquier llamada ajax. Puede adjuntarse a cualquier elemento; en mi ejemplo, acabo de elegir el body
porque está siempre presente
$("body").ajaxError(function(event, XMLHttpRequest, ajaxOptions, thrownError) {
if (XMLHttpRequest.status == 401) {
alert("unauthorized");
}
});
De esta forma, obtiene su lógica de redireccionamiento centralizada en un solo lugar, en lugar de tener que verificarla en cada maldita devolución de solicitud de ajax.
Solución 3, encabezado personalizado de devolución
Esta respuesta ofrece una solución alternativa. Utiliza el mismo tipo de controlador de eventos global, pero omite los bits hacky. Agrega un encabezado personalizado a la página si no está autenticado y la solicitud es una solicitud de Ajax, y verifica este encabezado en cada .ajaxComplete
. Tenga en cuenta que el método proporcionado en la respuesta vinculada no es seguro, ya que devolverá la vista original con contenido posiblemente confidencial y se basará en javascript para redirigir al usuario fuera de este. Con un poco de modificación es bastante impresionante, ya que no requiere ningún corte y la lógica se puede centralizar en una función de devolución de llamada. El único inconveniente que puedo ver es que no responde con el código de estado semánticamente correcto, ya que en realidad no es 200 OK
porque no está 401 Unauthorized
Podemos hornear esto en otra EnhancedAuthorizationAttribute
personalizada
public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAjaxRequest())
{
context.HttpContext.Response.AddHeader("REQUIRES_AUTH", "1");
context.Result = new EmptyResult();
}
else
{
base.HandleUnauthorizedRequest(context);
}
}
}
}
Ahora, cada vez que se completa una solicitud de Ajax, compruebe este encabezado:
$(''body'').ajaxComplete(function(event,request,settings){
if (request.getResponseHeader(''REQUIRES_AUTH'') === ''1''){
alert("unauthorized");
};
});
Tengo una vista que carga una vista parcial desde una acción del controlador usando jQuery. La acción del controlador está decorada con el atributo Autorizar y si el usuario ha agotado el tiempo cuando esa acción se llama redireccionamiento a la página LogOn apropiada, la página LogOn se inserta en la vista donde la vista parcial habría desaparecido.
Hay otra publicación here que describe una solución usando jQuery pero desafortunadamente no incluye muestras de código que es lo que necesito porque no estoy muy familiarizado con jQuery (y nuevo en el desarrollo web) y necesito resolver este problema tan pronto como puedo.
Todo lo que quiero hacer es redirigir al usuario a la página correcta de LogOn, que me suena muy directa, pero hasta ahora no parece ser así. Si jQuery es el camino a seguir, alguien podría publicar una muestra de código, eso realmente me ayudaría.
Gracias.
Para la segunda solución de Simen Echholt puede usar
$.ajaxSetup({ global: true,
statusCode: {
401: function () {
alert("unauthorized");
}
}
});
para vincular algunas funciones en el código de estado 401