返回部分视图的控制器操作会在授权失败时插入登录页面

fyn*_*bob 21 authentication asp.net-mvc jquery partial-views authorize-attribute

我有一个视图,使用jQuery从控制器操作加载部分视图.控制器操作使用Authorize属性进行修饰,如果用户在调用该操作被重定向到正确的LogOn页面时超时,则LogOn页面将插入到部分视图已经消失的视图中.

还有另一篇文章在这里描述使用jQuery但遗憾的是它不包含任何代码示例这正是我需要的,因为我不是很熟悉的jQuery(和新的Web开发)的解决方案,我需要得到这个问题的解决我会尽快.

我想要做的就是将用户重定向到正确的LogOn页面,这对我来说非常直接,但到目前为止它似乎并非如此.如果jQuery是要走的路,有人可以发一个代码示例,这真的会帮助我.

谢谢.

Sim*_*olt 33

解决方案1,返回响应指示错误


Pro ASP.NET MVC 2 Framework为此提供了一种解决方案

如果Ajax请求被拒绝授权,那么通常您不希望将HTTP重定向返回到登录页面,因为您的客户端代码不期望这样做并且可能会执行不需要的操作,例如将整个登录页面注入中间用户所在的任何页面.相反,您需要将更有用的信号发送回客户端代码(可能是JSON格式),以解释请求未经授权.您可以按如下方式实现:

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); 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

然后{'Error': 'NotAuthorized', 'LogonUrl': '...'},您将从控制器返回一个JSON对象,然后您可以使用该对象重定向用户.

如果您期望HTML,替代响应可能是返回一个纯字符串,NotAuthorized:<your_url>并检查响应是否与此模式匹配.


解决方案2,返回并处理401 Unautorized状态代码


由于必须在每个ajax请求的success回调中检查这一点,因此这非常繁琐.能够在全球范围内捕捉这个案例会很高兴.最好的解决方案是401 Unauthorized从服务器返回状态代码并使用jQuery .ajaxError来捕获它,但这在IIS/ASP.NET上是有问题的,因为如果响应具有此状态代码,它致命地将您重定向到登录页面.只要该重定向中<authentication>存在标记web.config就会发生[1]如果您不对其执行某些操作,.

让我们来做点什么吧.这个 hacky方式似乎很好.在你的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

(如果有人知道有什么更好的方法可以返回401状态代码,我很乐意听到它.)

通过这样做,当请求是ajax请求时,您将阻止重定向到登录页面的默认行为.因此,您可以AuthorizeAttribute按原样使用默认值,因为它Application_EndRequest 可以处理其余部分.

现在,在jQuery代码中,我们将使用该.ajaxError函数来捕获错误.这是一个全局的ajax事件处理程序,这意味着它将拦截任何ajax调用所产生的每个错误.它可以附加到任何元素 - 在我的例子中,我刚刚选择body因为它始终存在

$("body").ajaxError(function(event, XMLHttpRequest, ajaxOptions, thrownError) {
    if (XMLHttpRequest.status == 401) {
        alert("unauthorized");
    }
});
Run Code Online (Sandbox Code Playgroud)

这样你就可以将重定向逻辑集中在一个地方,而不必在每个该死的ajax请求成功回调上检查它


解决方案3,返回自定义标题


这个答案提供了另一种解决方案 它使用相同类型的全局事件处理程序,但跳过hacky位.如果您未经过身份验证并且请求是ajax请求,则会向页面添加自定义标头,并在每个请求上检查此标头.ajaxComplete.请注意,链接答案中提供的方法是不安全的,因为它将返回具有可能敏感内容的原始视图,并依赖于javascript将用户重定向到远离它.通过一些修改,它非常棒,因为它不需要任何黑客攻击,逻辑可以集中到一个回调函数.我能看到的唯一缺点就是它没有用语义正确的状态代码回复,因为它实际上不是200 OK因为你是401 Unauthorized


我们可以把它烘焙成另一种习俗 EnhancedAuthorizationAttribute

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,每次ajax请求完成时,都会检查此标头:

$('body').ajaxComplete(function(event,request,settings){
    if (request.getResponseHeader('REQUIRES_AUTH') === '1'){
        alert("unauthorized");
    };
});
Run Code Online (Sandbox Code Playgroud)