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