当用户未经过身份验证时,您如何处理ajax请求?

时间:2010-04-05 19:26:15

标签: asp.net ajax asp.net-mvc authentication

如果用户未经过身份验证,您如何处理ajax请求?

有人进入页面,离开房间一小时,返回,在使用jQuery($.post)的ajax页面上添加评论。由于未经过身份验证,因此方法返回RedirectToRoute结果(重定向到登录页面)。你用它做什么?你如何在客户端处理它以及如何在控制器中处理它?<​​/ p>

6 个答案:

答案 0 :(得分:16)

修改

我上面写了很久以前的回答,现在我相信发送403不是正确的方法。 403具有略微不同的含义,不应该使用它。这是使用401更正的属性。它仅与Http401Result中的其他context.HttpContext.Response.End()和不同的HTTP代码不同:

public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
    private class Http401Result : ActionResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            // Set the response code to 401.
            context.HttpContext.Response.StatusCode = 401;
            context.HttpContext.Response.Write(CTRes.AuthorizationLostPleaseLogOutAndLogInAgainToContinue);
            context.HttpContext.Response.End();
        }
    }

    private readonly bool _authorize;

    public OptionalAuthorizeAttribute()
    {
        _authorize = true;
    }

    //OptionalAuthorize is turned on on base controller class, so it has to be turned off on some controller. 
    //That is why parameter is introduced.
    public OptionalAuthorizeAttribute(bool authorize)
    {
        _authorize = authorize;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //When authorize parameter is set to false, not authorization should be performed.
        if (!_authorize)
            return true;

        var result = base.AuthorizeCore(httpContext);

        return result;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            //Ajax request doesn't return to login page, it just returns 401 error.
            filterContext.Result = new Http401Result();
        }
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}

OLD ANSWER:

虽然我喜欢其他答案中发布的想法(我之前已经了解过),但我需要代码示例。他们在这里:

修改授权属性:

public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
    private class Http403Result : ActionResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            // Set the response code to 403.
            context.HttpContext.Response.StatusCode = 403;
            context.HttpContext.Response.Write(CTRes.AuthorizationLostPleaseLogOutAndLogInAgainToContinue);
        }
    }

    private readonly bool _authorize;

    public OptionalAuthorizeAttribute()
    {
        _authorize = true;
    }

    //OptionalAuthorize is turned on on base controller class, so it has to be turned off on some controller. 
    //That is why parameter is introduced.
    public OptionalAuthorizeAttribute(bool authorize)
    {
        _authorize = authorize;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //When authorize parameter is set to false, not authorization should be performed.
        if (!_authorize)
            return true;

        var result = base.AuthorizeCore(httpContext);

        return result;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            //Ajax request doesn't return to login page, it just returns 403 error.
            filterContext.Result = new Http403Result();
        }
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}

HandleUnauthorizedRequest被覆盖,因此在使用Ajax时返回Http403ResultHttp403Result将StatusCode更改为403并将消息返回给用户作为响应。属性(authorize参数)中还有一些额外的逻辑,因为我在基本控制器中打开[Authorize]并在某些页面中禁用它。

另一个重要的部分是客户端对此响应的全局处理。这就是我在Site.Master中放置的内容:

<script type="text/javascript">
    $(document).ready(
        function() {
            $("body").ajaxError(
                function(e,request) {
                    if (request.status == 403) {
                        alert(request.responseText);
                        window.location = '/Logout';
                    }
                }
            );
        }
    );
</script>

我放置了一个GLOBAL ajax错误处理程序,当$.post因403错误而失败时,响应消息会被警告,用户将被重定向到注销页面。现在我不必处理每个$.post请求中的错误,因为它是全局处理的。

为什么403,而不是401? 401由MVC框架内部处理(这就是为什么在授权失败后重定向到登录页面的原因。)

你怎么看?

答案 1 :(得分:4)

当一位同事询问如何处理它时我提出的想法是 - 制作AuthorizeAjax属性。它可以询问并验证Request.IsAjaxRequest(),如果请求未经过身份验证,则返回特定的JSON错误对象。您可以简单地覆盖默认的AuthorizeAttribute并让它调用基数,除非它是未经授权的AJAX请求,因此您不必担心是否使用[Authorize]或[AuthorizeAjax]标记控制器操作。

在客户端,您必须配备所有页面来处理返回的错误,但可能会共享该逻辑。

答案 2 :(得分:2)

我建议创建自己的AuthorizeAttribute,如果请求是Ajax请求,则抛出HttpException(401/403)。并转而使用jQuery's Ajax Method代替。

假设您已实现错误页面并返回正确的状态代码,则会执行error回调而不是success回调。这将是因为响应代码而发生的。

答案 3 :(得分:0)

我发现的最简单,最干净的解决方案是使用jQuery.ajaxSuccess()事件注册回调,并检查“X-AspNetMvc-Version”响应头。

我的应用程序中的每个jQuery Ajax请求都由Mvc处理,所以如果标题丢失,我知道我的请求已被重定向到登录页面,我只是重新加载页面以进行顶级重定向:

 $(document).ajaxSuccess(function(event, XMLHttpRequest, ajaxOptions) {
    // if request returns non MVC page reload because this means the user 
    // session has expired
    var mvcHeaderName = "X-AspNetMvc-Version";
    var mvcHeaderValue = XMLHttpRequest.getResponseHeader(mvcHeaderName);

    if (!mvcHeaderValue) {
        location.reload();
    }
});

页面重新加载可能会导致一些Javascript错误(取决于您对Ajax响应所做的操作),但在大多数情况下,如果关闭调试,用户将永远不会看到这些错误。

如果您不想使用内置标题,我确信您可以轻松添加自定义标题,并遵循相同的模式。

答案 4 :(得分:0)

这是我使用的解决方案。如果有点蛮力,这很简单。我喜欢它,因为我很懒,我不想考虑动作方法的特殊属性,如果不需要,我不想编写ajax错误处理程序(尽管没有理由客户端脚本不能检测403状态代码并做一些用户友好的事情。

将它放在Global.axax中会检测到任何未经身份验证的ajax请求,只返回403,没有内容。这可以防止在使用表单身份验证时未经身份验证的ajax调用被重定向到登录表单。

 protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        // Prevent Ajax requests from being returned the login form when not authenticated
        // (eg. after authentication timeout).
        if ((Request.Headers["X-Requested-With"] != null && Request.Headers["X-Requested-With"] == "XMLHttpRequest")
            ||
            (Request["X-Requested-With"] != null && Request["X-Requested-With"] == "XMLHttpRequest"))
        {
            if (!Request.IsAuthenticated)
            {
                Response.Clear();
                Response.StatusCode = 403;
                Response.Flush();
                Response.End();
            }
        }
    }

答案 5 :(得分:0)

您可以检测ajax请求并发送401,在客户端,您甚至可以显示带有登录提示的ajax对话框,之后您可以继续&#34;继续&#34;您失败的ajax请求并使您的应用程序工作,用户感觉会话超时从未发生过。有关详细信息,请参阅this answer