Kendo UI ASP MVC 中的会话超时时,按钮单击不会将用户重定向到登录页面

san*_*084 3 authentication asp.net-mvc session redirect kendo-ui

我有一个 ASP MVC 页面,当会话过期时需要重定向到登录页面。如果用户位于页面中且会话过期,并且用户刷新页面,则用户将被重定向到登录页面。但是,如果用户单击按钮,页面永远不会重定向到登录页面。我在每个控制器操作方法中都有一个自定义 ActionFilter 来检查会话,并且我使用“RedirectToRouteResult”对象来重定向页面,但是它似乎仅在用户刷新页面时才起作用,而不是在单击按钮时起作用。

这是我的自定义操作过滤器:

public class CustomCheckSessionOutAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            string actionName = filterContext.ActionDescriptor.ActionName.ToLower().Trim();

            //Check Start with 
            if (!actionName.StartsWith("Login") && !actionName.StartsWith("LogOff"))
            {
                var session = HttpContext.Current.Session["LoggedInUserInfo"];

                //Redirects user to login screen if session has timed out
                if (session == null)
                {
                    base.OnActionExecuting(filterContext);

                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
                    {
                        controller = "Account",
                        action = "Login",
                        returnUrl = ((HttpRequestWrapper)((HttpContextWrapper)filterContext.HttpContext).Request).Url
                    }));

                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是控制器中操作方法的示例:

[Authorize(Roles = "Client")]
[CustomCheckSessionOut]
public ActionResult GetOrders([DataSourceRequest] DataSourceRequest request, string orderId)
{
}
Run Code Online (Sandbox Code Playgroud)

如果会话过期并且单击按钮,我有什么建议如何将用户重定向到登录页面?谢谢。

更新: 感谢 Fabien,我用他的方法解决了这个问题,如下所示:

全局.asax.cs

protected void Application_EndRequest()
        {
            var context = new HttpContextWrapper(Context);
            // If we're an ajax request, and doing a 302, then we actually need to do a 401
            if (Context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
            {
                Context.Response.Clear();
                Context.Response.StatusCode = 401;
                Context.Response.StatusDescription = "expiredSession";
            }
        }
Run Code Online (Sandbox Code Playgroud)

JavaScript:

$(document).ajaxComplete(function (e, xhr, options) {
    if (xhr != null) {
        if (xhr.getResponseHeader('X-Responded-JSON') != null) {
            var responseHeader = jQuery.parseJSON(xhr.getResponseHeader('X-Responded-JSON'));
            if (responseHeader.status === 401) {
                e.stopPropagation();
                window.location.href = responseHeader.headers.location;
            }
        }

        if (xhr.status === 401 && xhr.statusText === "expiredSession") {
            // Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event
            e.stopPropagation();
            location.reload();
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

Fab*_*NET 5

看来您的控制器操作是由 Kendo 组件使用 AJAX 调用的。您无法从 AJAX 调用重定向页面。您可以返回 HttpUnauthorizedResult,而不是返回 RedirectToRouteResult,在客户端使用 javascript 调用捕获它,如果状态代码为 401 - 未经授权,则触发页面重定向到您的登录操作。

您可以像这样更新自定义操作过滤器来处理这两种情况:

public class CustomCheckSessionOutAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string actionName = filterContext.ActionDescriptor.ActionName.ToLower().Trim();

        //Check Start with 
        if (!actionName.StartsWith("login") && !actionName.StartsWith("logoff"))
        {
            var session = filterContext.HttpContext.Session["LoggedInUserInfo"];

            //Redirects user to login screen if session has timed out
            if (session == null)
            {
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    // Indicate to the remote caller that the session has expired and where to redirect
                    filterContext.HttpContext.Response.Headers.Add("Location", new UrlHelper(filterContext.RequestContext).Action("Login", "Account"));       
                    filterContext.Result = new HttpUnauthorizedResult("Session expired");
                }
                else
                {
                    //Redirects user to login screen if session has timed out and request is non AJAX
                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
                    {
                        controller = "Account",
                        action = "Login",
                        returnUrl = filterContext.HttpContext.Request.Url
                    }));
                }                
            }
        }

        base.OnActionExecuting(filterContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑1:

Kendo grid 使用 DataSource 组件从远程源读取数据,它有一个名为“Error”的事件,您可以使用该事件来捕获 401 - 会话过期错误。

剃须刀代码:

@(Html.Kendo()
      .Grid<YourModel>()
      .Name("GridPOSearch")
      .DataSource(d => d.Ajax()
                        .Read("GetOrders", "YourController")
                        .Events(e => e.Error("error"))))
Run Code Online (Sandbox Code Playgroud)

JavaScript 代码:

function error(e) {
    if (e.errorThrown === "Session expired") {
        location.href = e.xhr.getResponseHeader("Location");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想在小部件初始化后绑定到错误事件,你可以这样做:

JavaScript 代码:

function datasource_error(e) {
    if (e.errorThrown === "Session expired") {
        location.href = e.xhr.getResponseHeader("Location");
    }
}

$("#GridPOSearch").data("kendoGrid").dataSource.bind("error", datasource_error);
Run Code Online (Sandbox Code Playgroud)

您可以替换“会话已过期”错误消息以更好地满足您的需要,只是不要忘记替换 JavaScript 代码中的检查,已在文档中显示

编辑2:

您可以使用 jQuery 1.0 及更高版本在应用程序范围内执行此操作,将此代码片段添加到每个页面上加载的 javascript 文件中(在您的 _Layout.cshtml 中):

(function () {
    $(document).ajaxComplete(function (e, xhr, options) {
        if (xhr.status === 401 && xhr.statusText === "Session expired") {
            // Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event
            e.stopPropagation();
            location.href = xhr.getResponseHeader("Location");                
        }
    });
})();
Run Code Online (Sandbox Code Playgroud)

我更新了动作过滤器和 kendo javascript 代码,以更优雅的方式设置重定向位置。