控制器需要认证用户的Ajax号召唤行动方法问题

时间:2009-08-28 14:58:36

标签: asp.net-mvc

使用我在最近的一个ASP.NET MVC书籍中找到的技术,我在控制器上有一个动作方法,它返回ajax请求的局部视图和正常获取请求的完整视图动作结果 - 它检查Request对象的IsAjaxRequest属性,用于确定要返回的action类型。 action方法返回的局部视图返回HTML以显示数据库中的记录表。包含操作方法的控制器使用Authorize属性进行标记,以便只有登录的用户才能调用控制器的方法。我正在使用表单身份验证,超时30分钟和滑动到期。

在达到用户30分钟超时后出现问题。由于控制器标有Authorize属性,因此在到期超时后调用action方法会将用户重定向到登录页面。但是,因为这是一个ajax调用,所以我的登录页面的html将返回并呈现在页面中间,该页面应该包含通常由部分视图中的action方法返回的记录的HTML表。 ajax调用并没有真正失败,只是返回错误页面的html。

有没有人遇到并处理过这个问题?我试图避免将处理ajax调用的所有服务器端代码移动到不需要经过身份验证的用户的单独控制器,但这似乎是我此时唯一的选择。即使这样也不会产生我期望的行为,因为即使在达到30分钟的超时后,它也会允许用户继续使用网页 - 它不会重定向到登录页面。

感谢您的任何建议。


修改

下面的解决方案使用自定义AuthorizeAttribute似乎让我朝着正确的方向前进,但我甚至无法使用此代码。似乎在达到到期超时后永远不会到达自定义AuthorizeAttribute中的代码。似乎表单身份验证导致在属性代码之前很久才重定向到登录页面。自定义AuthorizeAttribute是我控制器上唯一的一个。我还有以下web.config值(超时值设置得非常低,以触发测试超时):

<authentication mode="Forms">
        <forms loginUrl="~/Account/Login" timeout="1" slidingExpiration="true" defaultUrl="~/ErrorReport/Index" requireSSL="true" protection="All"/>
</authentication>
<authorization>
        <deny users="?"/>
        <allow users="*"/>
</authorization>
<location path="Content">
        <system.web>
            <authorization>
                <allow users="*"/>
            </authorization>
        </system.web>
    </location>
<location path="Scripts">
        <system.web>
            <authorization>
                <allow users="*"/>
            </authorization>
        </system.web>
</location>

授权 web.config元素是否会妨碍?我不应该在ASP.NET MVC中使用它们吗?

2 个答案:

答案 0 :(得分:6)

我实际上有一篇关于此排队的博客文章,我会在评论发布后添加到评论中,但是现在正在发生这种情况。

在较高级别,当ASP.NET运行时看到401响应代码时,它会自动将其转换为重定向并将用户发送到登录页面。你想要做的是绕过401

在MVC中,当您使用AuthorizeAttribute时,它会检查用户是否已获得授权,如果没有,则返回HttpUnauthorizedResult。这基本上迫使运行时将用户重定向到登录页面。您想要做的是覆盖此行为。

为此,请扩展AuthorizeAttribute:

public class AuthorizeWithAjaxAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.Result is HttpUnauthorizedResult && filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = 200;
            filterContext.Result = /* Some result recognized by the client */
        }
    }
}

当你发出一个AJAX请求并且响应的数据等于你返回的过滤器上下文的结果时,只需通过javascript将用户重定向到登录页面。

答案 1 :(得分:1)

是的,这个问题很常见。它还有一个简单的解决方案 - 在处理AJAX响应的Javascript部分,在使用响应之前检查超时。如果发生超时,请将用户重定向到登录页面。

或者,如果服务器端脚本本身正在检查会话超时(这似乎是你的情况),它变得更加简单。不要返回整个登录页面,而只是返回“need_login”之类的标志。此外,只需编写Javascript处理程序以检查返回的值是否为“need_login”,如果为true,则加载登录页面。