8

我们在整个应用程序中使用 Ajax 调用——试图找出一个全局解决方案,如果在尝试执行任何 Ajax 请求时会话已经过期,则重定向到登录页面。我已经编写了以下解决方案,从这篇文章中获取帮助 -处理 ajax 调用中的会话超时

不知道为什么在我的关心事件中“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);
            }

        }

    }

在控制器操作中使用上述自定义属性如下:

 [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”不会被触发 - 请有任何想法。

谢谢,

@保罗

4

5 回答 5

2

如果我的问题是正确的(即使我没有,无论如何,谢谢,帮助我解决了我自己的情况),你想要避免的是让你的登录页面加载到一个应该显示不同视图的元素中阿贾克斯。或者在 Ajax 表单发布期间获得异常/错误状态代码。

因此,简而言之,注释类将需要覆盖 2 个方法,而不仅仅是HandleUnauthorizedRequest,并且它将重定向到一个 JsonResult 操作,该操作将为您的 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" }));
        }
    }
}

然后在你的身份验证Action中设置这个注解,这样每次调用它都会知道请求来自哪里,应该给出什么样的返回。

[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");
        });
    });
});

该函数将html标签替换为该data-ajax-render-html属性,该属性包含您要加载的View地址,但您可以通过更改属性将其设置为在标签内replaceWith加载html()

于 2017-09-27T17:23:58.273 回答
1

我认为这只是一个客户端问题。在 Web 服务器中,您可以在操作或控制器上使用经典的Authorize属性。这将验证请求是否已通过身份验证(如果有有效的身份验证 cookie 或授权标头),如果未通过身份验证,则设置 HTTP 401。

注意:如果您在请求中不发送授权信息,会话将自动重新创建,但请求不会被授权

解决方案

然后你必须处理重定向的javascript客户端(浏览器会自动完成,但使用ajax你需要手动完成)

$.ajax({
    type: "GET",
    url: "/Customer/GetSomething",
    statusCode: {
       401: function() {
          // do redirect to your login page
          window.location.href = '/default.aspx'
       }
    }
});
于 2017-09-26T15:30:19.617 回答
0

在 HttpContext.Request.IsAjaxRequest()

请参阅这篇相关文章,了解为什么 Ajax 请求可能无法被识别。

XMLHttpRequest() 不被识别为 IsAjaxRequest?

看起来在请求中存在对某个标头值(X-Requested-With)的依赖性,以便该函数返回 true。

您可能希望捕获并查看您的流量和服务器标头,以查看浏览器是否确实正确发送了此值。

但是,你确定它会命中那行代码吗? 您可能还想使用断点进行调试并查看设置了哪些值。

会话与身份验证

授权和会话超时并不总是完全相同。一个人实际上可以授予比会话更长的授权,如果会话丢失,只要它们已经被授权,就重建它。如果您发现会话中有一些您将丢失且无法重建的东西,那么也许您应该将它移到其他地方,或者另外将其保留在其他地方。

表单身份验证cookie 默认在30 分钟后超时。 会话超时默认为20 分钟

ASP.NET 中的会话超时

HandleUnauthorizedRequest 未覆盖

于 2017-09-26T15:27:12.030 回答
0

我检查并测试了代码,看起来很清楚..问题是ajax调用错误..

我修复了 Ajax 代码,试试这个..

function GetSomething() {
        $.ajax({
            cache: false,
            type: "GET",
            async: true,
            url: "/Customer/GetSomething",
            success: function (data) {

            },
            error: function (xhr, ajaxOptions, thrownError) {

            }
        });
    }
于 2017-09-21T09:45:04.197 回答
0

很抱歉地说:您需要的解决方案是不可能的。原因是:

  • 要将用户重定向到登录页面,我们有两种方法:在服务器重定向,在客户端重定向
  • 在您的情况下,您使用的是 Ajax,所以我们只有一种方法:在客户端重定向(原因基本上是,Ajax 意味着向/从服务器发送/检索数据。所以不可能在服务器上重定向)
  • 接下来,在客户端重定向。Ajax 需要来自服务器的信息说“将用户重定向到登录页面”,而全局检查会话方法必须返回 Redirect(“url here”)。
  • 显然,全局检查会话方法不能返回 2 类型(返回 Redirect()、返回 Json、Xml、Object 或字符串)

毕竟,我建议:

  • 解决方案 1:不要使用 ajax
  • 解决方案 2:您可以使用 ajax,但在不是全局的服务器上检查会话超时方法。意味着你必须多次实现(ajax调用的数量=实现的数量)
于 2017-09-27T10:37:44.480 回答