原文:https://www.cnblogs.com/Locked-J/p/7700070.html
笔记:
可以在权限验证的时候判断是不是ajax请求,如果是,就返回status 0,然后页面去处理,如果不是 就redirect
【Ajax Asp.Net】Ajax跨域重定向302及错误回调 、MVC身份验证过滤器
一、身份验证拦截,Ajax请求跨域重定向到页面后不加载,场景分析
业务场景
目前项目需要使用公司的OAuth身份验证平台做单点登录(Single Sign On,SSO),于是要在目前的MVC项目中添加身份验证相关的业务逻辑,项目中大量表格展示数据,使用了很多Ajax。我对项目大部分请求做了身份验证,Ajax请求也要拦截。
问题
对未登录用户发起的的Ajax请求,返回重定向的登录页,但是实际页面并不会加载得到的登录页面。
分析
Ajax本就为页面局部刷新修改而做的,返回的页面只会被当做返回的普通数据。
在过滤器中身份验证未通过后,请求被重定向(302
)了项目的login方法,然后根据项目信息重定向(302
)到认证平台的对应登录页面(200
),浏览器拦截跨域请求资源,此时返回给Ajax的Http状态码为0
(就是没有返回状态码的情况)。于是,需要针对返回到Ajax的状态码为0时,做处理。
处理方法
在全局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);
}
if (xhr.status === 404) {
if (xhr.status === 500) {
console.log(xhr);
}
});
小结
这里暂时处理,返回状态码0的时候直接强制刷新页面,然后对页面刷新的身份验证拦截重定向到登录页。
考虑修改,验证请求类型为Ajax请求时,身份验证失败直接返回失败响应状态码,并使用Js直接重定向到登录页面,省去无效重定向。
续:
使用Request.IsAjaxRequest();
可以判断请求类型,然后就方便处理了。
二、MVC自定义动态错误页面后,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>
override void OnAuthorization(AuthorizationContext filterContext) {
base.OnAuthorization(filterContext); //进入AuthorizeCore
}
/// <summary>
/// 自定义授权检查(返回False则授权失败)
/// </summary>
protected 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;
false; // 进入HandleUnauthorizedRequest
}
/// <summary>
/// 处理授权失败的HTTP请求
/// </summary>
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");
}
}
}
}