首页 文章

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

提问于
浏览
0

我有一个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
                    }));

                }
            }
        }
    }

以下是Controller中的操作方法示例:

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

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

UPDATE: 感谢Fabien,我用他的方法让它像这样解决:

Global.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";
            }
        }

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();
        }
    }
});

1 回答

  • 1

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

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

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

    编辑1:

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

    剃刀代码:

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

    Javascript代码:

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

    如果要在窗口小部件启动后绑定到错误事件,可以这样做:

    Javascript代码:

    function datasource_error(e) {
        if (e.errorThrown === "Session expired") {
            location.href = e.xhr.getResponseHeader("Location");
        }
    }
    
    $("#GridPOSearch").data("kendoGrid").dataSource.bind("error", datasource_error);
    

    您可以替换"Session expired"错误消息以更好地满足您的需求,只是不要忘记更换javascript代码中的检查,已在documentation上显示 .

    编辑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");                
            }
        });
    })();
    

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

相关问题