Asp.net mvc 在未经授权的情况下,如何重定向到登录屏幕,同时在MVC中返回401状态码?

Asp.net mvc 在未经授权的情况下,如何重定向到登录屏幕,同时在MVC中返回401状态码?,asp.net-mvc,Asp.net Mvc,在我们的MVC网站上,我们使用Authorize属性保护我们的端点,但是当出现这种情况时,我想将用户重定向到登录屏幕。我的第一个解决方案是在Global.asax.cs中重定向Application\u EndRequest: protected void Application_EndRequest(object sender, EventArgs e) { if (Response.StatusCode == (int) HttpStatusCode.Unau

在我们的MVC网站上,我们使用
Authorize
属性保护我们的端点,但是当出现这种情况时,我想将用户重定向到登录屏幕。我的第一个解决方案是在
Global.asax.cs
中重定向
Application\u EndRequest

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        if (Response.StatusCode == (int) HttpStatusCode.Unauthorized)
        {
            Response.ClearContent();
            Response.Redirect("/Account/Login");
        }
    }
问题是我们的一些视图是由AJAX加载的,在这种情况下,我们不希望在动态加载的div中显示登录屏幕(例如,当注销后按下back按钮时)。如果请求仍然返回登录屏幕,但带有401未经授权的状态代码,以便我们能够检测到此事件,那就更好了。显然,这种方法不起作用,因为重定向依赖于302状态码

相反,我宁愿用401状态代码“插入”登录屏幕内容到
Application\u EndRequest
。因此,我没有使用
Response.Redirect
,而是尝试了以下方法:

            ...
            Response.ClearContent();
            Server.TransferRequest("~/Account/Login");
            Response.StatusCode = (int) HttpStatusCode.Unauthorized;
            ...
重定向工作得很好,但是因为它执行一个新的请求,所以我不能用这种方式设置状态代码,我得到了一个200。仍然无法检测未经授权的请求

我还尝试:

            ...
            Response.ClearContent();
            Server.Transfer("~/Account/Login");
            Response.StatusCode = (int) HttpStatusCode.Unauthorized;
            ...
            ...
            Response.ClearContent();
            HttpContext.Current.RewritePath("~/Account/Login");
            Response.StatusCode = (int) HttpStatusCode.Unauthorized;
            Response.End();
            ...
但我得到一个异常“执行/Account/Login的子请求时出错”

我还尝试:

            ...
            Response.ClearContent();
            Server.Transfer("~/Account/Login");
            Response.StatusCode = (int) HttpStatusCode.Unauthorized;
            ...
            ...
            Response.ClearContent();
            HttpContext.Current.RewritePath("~/Account/Login");
            Response.StatusCode = (int) HttpStatusCode.Unauthorized;
            Response.End();
            ...
但这会引发一个异常“线程正在中止”。我不确定Response.End()是否必要,但如果没有它,我只会得到一个标准的IIS 401错误


我怎样才能返回登录屏幕上的内容,但带有401状态码?

我尝试了很多不同的方法,所有这些方法都有自己的隐秘问题。不确定您的解决方案是如何设置的,但如果您需要执行传输,可以使用以下方法:

自定义属性 您需要将消息传递给下一个请求,使用QueryString似乎可以做到这一点。尽管您需要记住,任何人都可以设置QS参数

设置状态代码 演示 没有重定向,HTTP状态代码设置为401


发送401和ViewObject或RedirectObject并不是MVC框架设计的工作方式:一些帖子巧妙地表明,返回带有授权过滤器的视图的401

我指定了MVC框架,但这甚至不是使用HTTP协议的首选方式

  • 当您在MVC应用程序中重定向时,您已经创建了一个
  • 当MVC应用程序返回并调用控制器的
    View()
    方法时,将创建一个
无论重定向还是视图最终到达客户端浏览器

  • 一个
    HTTP返回码
    200--Success将被返回

  • 将返回302的
    HTTP返回码--重定向
此约定的原因是,服务器正在“处理”重定向。如果用户未经授权,服务器将用户重定向到登录页面

同样,在AJAX或异步HTTP请求中,只要返回HTML视图,HTTP请求就被视为成功。异步请求不返回重定向(302)


向客户端发送错误代码:

如果要将
401
未经授权的返回给客户端,通常意味着您希望客户端通过导航到登录或错误视图来“处理”未经授权的请求

$.ajax({
    url: loginURL,
    data: $("#form").serialize(),
    type: "POST",
    dataType: "html"
})
.success(function (result, status) {
            /*additional logic*/
})
.error(function (xhr, status) {
    if (xhr.status == 401)
    {
        window.location = unauthorizedUrl; //redirect to unauthorized url
    }
});

如果要重定向到登录页面并显示错误,该怎么办

如果您想重定向到登录页面并显示错误,您的问题最有意义

然后,惯例是将错误消息添加到
Viewbag
或ModelState错误中

例如:

        var user = await signInManager.UserManager.FindByNameAsync(model.UserName);

                ModelState.AddModelError("", "Invalid username or password.");
                return View(model);
在您看来,要使代码查找错误:

ValidationSummary
将拾取模型错误

            @Html.ValidationSummary(true)

这个错误登录尝试的具体示例与您的示例并不完全相符


我找不到重定向用户的图像,因为他们未经授权,但在本例中,逻辑类似。Error Msg可以用QueryString、Viewbag等填充。

理想情况下,您需要使用自定义的
authorizatorAttribute
,然后连接到
HandleUnauthorizedRequest
方法,然后通过将控制器和视图设置为在AuthorizationContext中调用,将视图返回到登录页面

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.RouteData.Values["controller"] = "home";
            filterContext.RouteData.Values["action"] = "login";

            filterContext.Result = new ViewResult ();
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        }
    }
}
注意:这样做的诀窍是确保将以下值设置为true,以避免表单身份验证在设置401状态后接管响应

HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

尝试使用401设置的自定义错误处理返回登录视图。在我下面提供的答案中,我返回一个ViewObject和一个401状态代码。@timkly,你是对的。我应该编辑我的帖子,承认这显然是可能的。