身份验证拦截,Ajax请求跨域重定向到页面后不加载,场景分析

原文:https://www.cnblogs.com/Locked-J/p/7700070.html

笔记:

可以在权限验证的时候判断是不是ajax请求,如果是,就返回status 0,然后页面去处理,如果不是 就redirect


【Ajax Asp.Net】Ajax跨域重定向302及错误回调 、MVC身份验证过滤器

一、身份验证拦截,Ajax请求跨域重定向到页面后不加载,场景分析

关键字:身份验证拦截 Ajax 跨域 重定向 302

业务场景

目前项目需要使用公司的OAuth身份验证平台做单点登录(Single Sign On,SSO),于是要在目前的MVC项目中添加身份验证相关的业务逻辑,项目中大量表格展示数据,使用了很多Ajax。我对项目大部分请求做了身份验证,Ajax请求也要拦截。

问题

对未登录用户发起的的Ajax请求,返回重定向的登录页,但是实际页面并不会加载得到的登录页面。

分析

Ajax本就为页面局部刷新修改而做的,返回的页面只会被当做返回的普通数据。
在过滤器中身份验证未通过后,请求被重定向(302)了项目的login方法,然后根据项目信息重定向(302)到认证平台的对应登录页面(200),浏览器拦截跨域请求资源,此时返回给Ajax的Http状态码为0(就是没有返回状态码的情况)。于是,需要针对返回到Ajax的状态码为0时,做处理。
被拦截Ajax请求的情况

处理方法

在全局js中添加Ajax的请求错误回调设置方法(还有其他方法ajaxComplete之类的,见W3CSchool)

/*ajax请求失败回调默认方法*/
$(document).ajaxError(function (event, xhr, options, exc) {
    if (xhr.status === 0) {
        window.location.reload();    // 强制刷新页面
    }
    else if (xhr.status === 302) {
        console.log(xhr);
    }
    else if (xhr.status === 404) {
        console.log(xhr);
    }
    else if (xhr.status === 500) {
        console.log(xhr);
    }
});

小结

这里暂时处理,返回状态码0的时候直接强制刷新页面,然后对页面刷新的身份验证拦截重定向到登录页。
考虑修改,验证请求类型为Ajax请求时,身份验证失败直接返回失败响应状态码,并使用Js直接重定向到登录页面,省去无效重定向。

续:

使用Request.IsAjaxRequest();可以判断请求类型,然后就方便处理了。

二、MVC自定义动态错误页面后,Ajax错误回调方法接收不到对应状态码

关键字: Ajax http状态码

业务场景

MVC项目的错误页面自定义(即通过控制器获取Razor视图而不是HTML静态页面)后,Ajax的请求接收到Http状态码只有200的情况。
(静态的页面,MVC可以在Web.config中配置状态码)

分析

错误被拦截后,动态重定向到指定控制器方法后,正常返回页面,所以状态码是200。

处理方法

Response.StatusCode = 500;
控制器对应方法返回动态的错误页面时,先修改响应状态码,然后Ajax就可以收到错误了,可以像上面一个问题里拦截回调处理,做提示一下之类的操作。

总结

写完发现都是小问题。扶额。(╯‵□′)╯︵┻━┻。好菜。

MVC身份验证过滤器

类似下面的,过滤器主要进行身份验证,跳转SSO的认证平台及存储获取的令牌等操作由/login进行,不在此记录。

using System.Web;
using System.Web.Mvc;

namespace Filter
{
    /// <summary>
    /// 身份验证过滤器
    /// 使用方法:[CustAuthorize]特性
    /// 1.特性可以使用在Class和Method上,Class上表示内部所有方法需要验证
    /// 2.可以Class上[CustAuthorize]并在不需要验证的方法上[AllowAnonymous]
    /// </summary>
    public class CustAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 请求的地址
        /// </summary>
        private string requestUrl { get; set; }

        /// <summary>
        /// 请求授权时执行
        /// </summary>
        public override void OnAuthorization(AuthorizationContext filterContext) {
            base.OnAuthorization(filterContext);   //进入AuthorizeCore
        }

        /// <summary>
        /// 自定义授权检查(返回False则授权失败)
        /// </summary>
        protected override bool AuthorizeCore(HttpContextBase httpContext) {
            if (httpContext.Session["tk"] != null && !string.IsNullOrEmpty(httpContext.Session["tk"].ToString()))
            {
                string tk = httpContext.Session["tk"].ToString();    // 令牌,获取到以后存在Session了,
                bool check = Check.check(tk);    // 验证方法
                if (check)
                    return true;
            }
            httpContext.Session["tk"] = null;
            return false;     // 进入HandleUnauthorizedRequest 
        }

        /// <summary>
        /// 处理授权失败的HTTP请求
        /// </summary>
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
            if (filterContext.HttpContext.Request.IsAjaxRequest())  // ajax请求
            {
                filterContext.HttpContext.Response.StatusCode = 302;
                var json = JsonConvert.SerializeObject(new { state = "0", message = "权限验证失败!请重新登录" });
                filterContext.HttpContext.Response.Write(json);
                filterContext.HttpContext.Response.End();
            }
            else // 未登录请求页面地址
            {
                filterContext.HttpContext.Session["requestUrl"] = filterContext.HttpContext.Request.Url.AbsolutePath;
                // 重定向到登录
                filterContext.Result = new RedirectResult("/login");
            }
        }
    }
}
相关文章
相关标签/搜索