Asp.net MVC - 如何检查 Ajax 请求的会话过期
Asp.net MVC - How to check session expire for Ajax request
我们在整个应用程序中使用 Ajax 调用 - 试图找到一个全局解决方案,如果在尝试执行任何 Ajax 请求时会话已经过期,则重定向到登录页面。我已经编写了以下解决方案,从这个 post - Handling session timeout in ajax calls
获得帮助
不确定为什么在我的护理事件中 "HandleUnauthorizedRequest" 没有被解雇。
自定义属性:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CheckSessionExpireAttribute :AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var url = new UrlHelper(filterContext.RequestContext);
var loginUrl = url.Content("/Default.aspx");
filterContext.HttpContext.Session.RemoveAll();
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.HttpContext.Response.Redirect(loginUrl, false);
filterContext.Result = new EmptyResult();
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
在控制器操作中使用 Above 自定义属性如下:
[NoCache]
[CheckSessionExpire]
public ActionResult GetSomething()
{
}
AJAX调用(JS部分):
function GetSomething()
{
$.ajax({
cache: false,
type: "GET",
async: true,
url: "/Customer/GetSomething",
success: function (data) {
},
error: function (xhr, ajaxOptions, thrownError) {
}
}
Web Config 身份验证设置:
<authentication mode="Forms">
<forms loginUrl="default.aspx" protection="All" timeout="3000" slidingExpiration="true" />
</authentication>
我尝试通过在进行 ajax 调用之前删除浏览器烹饪来检查它,但是事件 "CheckSessionExpireAttribute " 没有被触发 - 请知道任何想法。
谢谢,
@保罗
我检查并测试了代码,看起来很清楚..问题是ajax调用错误..
我修复了 Ajax 代码,试试这个..
function GetSomething() {
$.ajax({
cache: false,
type: "GET",
async: true,
url: "/Customer/GetSomething",
success: function (data) {
},
error: function (xhr, ajaxOptions, thrownError) {
}
});
}
在HttpContext.Request.IsAjaxRequest()
请参阅这篇相关文章,了解为什么 Ajax 请求可能无法被识别。
XMLHttpRequest() not recognized as a IsAjaxRequest?
It looks like there is a dependency on a certain header value (X-Requested-With) being in the request in order for that function to return true.
您可能想要捕获并查看您的流量,并headers到服务器以查看浏览器是否确实正确地发送了这个值。
但是,你确定它会碰到那行代码吗?你可能还想调试 断点 并查看设置了哪些值。
在 Session 与身份验证
授权和Session超时并不总是完全相同。实际上可以授予比 session 更长期限的授权,如果缺少 session,只要他们已经获得授权,就重建它。如果您发现 session 上有一些您将丢失且无法重建的东西,那么也许您应该将其移到其他地方,或者另外将其保留在其他地方。
表单身份验证 cookie 默认在 30 分钟 后超时。 Session 超时默认为 20 分钟.
我认为这只是一个 client-side 问题。
在 Web 服务器中,您可以只对操作或控制器使用经典的 Authorize 属性。
这将验证请求是否已通过 身份验证(如果存在有效的身份验证 cookie 或授权 header),如果未通过身份验证则设置 HTTP 401。
Note: a session will automatically be recreated if you don't send authorization info in the request, but the request will not be authorized
解决方案
然后 javascript 客户端您 必须 处理重定向(浏览器会自动执行,但对于 ajax 您需要手动执行)
$.ajax({
type: "GET",
url: "/Customer/GetSomething",
statusCode: {
401: function() {
// do redirect to your login page
window.location.href = '/default.aspx'
}
}
});
很抱歉地说:您需要的解决方案不可能。原因是:
- 要将用户重定向到登录页面,我们有两种方法:在服务器重定向,在客户端重定向
- 在你的例子中,你使用的是 Ajax 所以我们只有一种方法:在客户端重定向(原因基本上是,Ajax 意味着 send/retrieve 数据 to/from 服务器。所以不可能在服务器重定向)
- 接下来,在客户端重定向。 Ajax 需要来自服务器的信息说 "redirect user to login page" 而全局检查会话方法必须是 return Redirect("url here").
- 显然,全局检查会话方法不能return 2 type (return Redirect(), return Json,Xml,Object,or字符串)
毕竟我建议:
- 解决方案 1:不要使用 ajax
- 解决方案 2:您可以使用 ajax,但请检查非全局服务器上的会话超时方法。意味着你必须多个实现(ajax调用的数量=实现的数量)
如果我答对了问题(即使我没有答对,无论如何谢谢,帮助我解决了我自己的问题),你想要避免的是让你的登录页面加载到一个元素中,这个元素应该是通过 Ajax 显示不同的视图。或者在 Ajax 表单 post.
期间获得 exception/error 状态代码
所以,简而言之,注释 class 将需要重写 2 个方法,而不仅仅是 HandleUnauthorizedRequest
,它会重定向到一个 JsonResult Action 来生成参数让你的 Ajax 函数知道该做什么。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class SessionTimeoutAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
IPrincipal user = filterContext.HttpContext.User;
base.OnAuthorization(filterContext);
if (!user.Identity.IsAuthenticated) {
HandleUnauthorizedRequest(filterContext);
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "AccountController", action = "Timeout" }));
}
}
}
然后在你的authentication Action中设置这个annotation,这样每次调用它的时候,它就会知道请求来自哪里,应该给什么样的return。
[AllowAnonymous]
[SessionTimeout]
public ActionResult Login() { }
然后您的重定向 Json 操作:
[AllowAnonymous]
public JsonResult Timeout()
{
// For you to display an error message when the login page is loaded, in case you want it
TempData["hasError"] = true;
TempData["errorMessage"] = "Your session expired, please log-in again.";
return Json(new
{
@timeout = true,
url = Url.Content("~/AccountController/Login")
}, JsonRequestBehavior.AllowGet);
}
然后在您的客户端函数中(我有幸将其写为 $.get()
而不是 $.ajax()
:
$(document).ready(function () {
$("[data-ajax-render-html]").each(function () {
var partial = $(this).attr("data-ajax-render-html");
var obj = $(this);
$.get(partial, function (data) {
if (data.timeout) {
window.location.href = data.url;
} else {
obj.replaceWith(data);
}
}).fail(function () {
obj.replaceWith("Error: It wasn't possible to load the element");
});
});
});
这个函数用这个data-ajax-render-html
属性替换了html标签,里面包含了你要加载的View地址,但是你可以通过改变[=18]来设置在标签内部加载=] 对于 html()
属性.
我们在整个应用程序中使用 Ajax 调用 - 试图找到一个全局解决方案,如果在尝试执行任何 Ajax 请求时会话已经过期,则重定向到登录页面。我已经编写了以下解决方案,从这个 post - Handling session timeout in ajax calls
获得帮助不确定为什么在我的护理事件中 "HandleUnauthorizedRequest" 没有被解雇。
自定义属性:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CheckSessionExpireAttribute :AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var url = new UrlHelper(filterContext.RequestContext);
var loginUrl = url.Content("/Default.aspx");
filterContext.HttpContext.Session.RemoveAll();
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.HttpContext.Response.Redirect(loginUrl, false);
filterContext.Result = new EmptyResult();
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
在控制器操作中使用 Above 自定义属性如下:
[NoCache]
[CheckSessionExpire]
public ActionResult GetSomething()
{
}
AJAX调用(JS部分):
function GetSomething()
{
$.ajax({
cache: false,
type: "GET",
async: true,
url: "/Customer/GetSomething",
success: function (data) {
},
error: function (xhr, ajaxOptions, thrownError) {
}
}
Web Config 身份验证设置:
<authentication mode="Forms">
<forms loginUrl="default.aspx" protection="All" timeout="3000" slidingExpiration="true" />
</authentication>
我尝试通过在进行 ajax 调用之前删除浏览器烹饪来检查它,但是事件 "CheckSessionExpireAttribute " 没有被触发 - 请知道任何想法。
谢谢,
@保罗
我检查并测试了代码,看起来很清楚..问题是ajax调用错误..
我修复了 Ajax 代码,试试这个..
function GetSomething() {
$.ajax({
cache: false,
type: "GET",
async: true,
url: "/Customer/GetSomething",
success: function (data) {
},
error: function (xhr, ajaxOptions, thrownError) {
}
});
}
在HttpContext.Request.IsAjaxRequest()
请参阅这篇相关文章,了解为什么 Ajax 请求可能无法被识别。
XMLHttpRequest() not recognized as a IsAjaxRequest?
It looks like there is a dependency on a certain header value (X-Requested-With) being in the request in order for that function to return true.
您可能想要捕获并查看您的流量,并headers到服务器以查看浏览器是否确实正确地发送了这个值。
但是,你确定它会碰到那行代码吗?你可能还想调试 断点 并查看设置了哪些值。
在 Session 与身份验证
授权和Session超时并不总是完全相同。实际上可以授予比 session 更长期限的授权,如果缺少 session,只要他们已经获得授权,就重建它。如果您发现 session 上有一些您将丢失且无法重建的东西,那么也许您应该将其移到其他地方,或者另外将其保留在其他地方。
表单身份验证 cookie 默认在 30 分钟 后超时。 Session 超时默认为 20 分钟.
我认为这只是一个 client-side 问题。 在 Web 服务器中,您可以只对操作或控制器使用经典的 Authorize 属性。 这将验证请求是否已通过 身份验证(如果存在有效的身份验证 cookie 或授权 header),如果未通过身份验证则设置 HTTP 401。
Note: a session will automatically be recreated if you don't send authorization info in the request, but the request will not be authorized
解决方案
然后 javascript 客户端您 必须 处理重定向(浏览器会自动执行,但对于 ajax 您需要手动执行)
$.ajax({
type: "GET",
url: "/Customer/GetSomething",
statusCode: {
401: function() {
// do redirect to your login page
window.location.href = '/default.aspx'
}
}
});
很抱歉地说:您需要的解决方案不可能。原因是:
- 要将用户重定向到登录页面,我们有两种方法:在服务器重定向,在客户端重定向
- 在你的例子中,你使用的是 Ajax 所以我们只有一种方法:在客户端重定向(原因基本上是,Ajax 意味着 send/retrieve 数据 to/from 服务器。所以不可能在服务器重定向)
- 接下来,在客户端重定向。 Ajax 需要来自服务器的信息说 "redirect user to login page" 而全局检查会话方法必须是 return Redirect("url here").
- 显然,全局检查会话方法不能return 2 type (return Redirect(), return Json,Xml,Object,or字符串)
毕竟我建议:
- 解决方案 1:不要使用 ajax
- 解决方案 2:您可以使用 ajax,但请检查非全局服务器上的会话超时方法。意味着你必须多个实现(ajax调用的数量=实现的数量)
如果我答对了问题(即使我没有答对,无论如何谢谢,帮助我解决了我自己的问题),你想要避免的是让你的登录页面加载到一个元素中,这个元素应该是通过 Ajax 显示不同的视图。或者在 Ajax 表单 post.
期间获得 exception/error 状态代码所以,简而言之,注释 class 将需要重写 2 个方法,而不仅仅是 HandleUnauthorizedRequest
,它会重定向到一个 JsonResult Action 来生成参数让你的 Ajax 函数知道该做什么。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class SessionTimeoutAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
IPrincipal user = filterContext.HttpContext.User;
base.OnAuthorization(filterContext);
if (!user.Identity.IsAuthenticated) {
HandleUnauthorizedRequest(filterContext);
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "AccountController", action = "Timeout" }));
}
}
}
然后在你的authentication Action中设置这个annotation,这样每次调用它的时候,它就会知道请求来自哪里,应该给什么样的return。
[AllowAnonymous]
[SessionTimeout]
public ActionResult Login() { }
然后您的重定向 Json 操作:
[AllowAnonymous]
public JsonResult Timeout()
{
// For you to display an error message when the login page is loaded, in case you want it
TempData["hasError"] = true;
TempData["errorMessage"] = "Your session expired, please log-in again.";
return Json(new
{
@timeout = true,
url = Url.Content("~/AccountController/Login")
}, JsonRequestBehavior.AllowGet);
}
然后在您的客户端函数中(我有幸将其写为 $.get()
而不是 $.ajax()
:
$(document).ready(function () {
$("[data-ajax-render-html]").each(function () {
var partial = $(this).attr("data-ajax-render-html");
var obj = $(this);
$.get(partial, function (data) {
if (data.timeout) {
window.location.href = data.url;
} else {
obj.replaceWith(data);
}
}).fail(function () {
obj.replaceWith("Error: It wasn't possible to load the element");
});
});
});
这个函数用这个data-ajax-render-html
属性替换了html标签,里面包含了你要加载的View地址,但是你可以通过改变[=18]来设置在标签内部加载=] 对于 html()
属性.