Asp.Net MVC如何返回401响应码

需求:
    在默认创建的Asp.Net MVC项目中(这里使用VS2013),需要手动返回一个401响应码给浏览器。我们的代码可能是下面这样子的。
 
  1. 1         public ActionResult UnauthorizedAccess()
    2         {
    3             return new HttpStatusCodeResult((int)HttpStatusCode.Unauthorized);
    4         }
 
实际的效果却和预期的不太一样,如果我们是通过地址栏直接访问这个Action,可以看到请求被重定向到登录页面了
 
 
如果通过Ajax的方式进行访问,可以看到直接返回了一个200的响应码
 
因为当前创建的MVC项目默认使用的是一个叫CookieAuthentication的OWIN中间件来实现身份认证的功能的,该中间件中会将401响应码进行特殊处理,所以导致我们无法手动返回401响应码。
 
Startup类中的代码: 
  1.  1             // 使应用程序可以使用 Cookie 来存储已登录用户的信息
     2             // 并使用 Cookie 来临时存储有关使用第三方登录提供程序登录的用户的信息
     3             // 配置登录 Cookie
     4             app.UseCookieAuthentication(new CookieAuthenticationOptions
     5             {
     6                 AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
     7                 LoginPath = new PathString("/Account/Login"),
     8                 Provider = new CookieAuthenticationProvider
     9                 {
    10                     // 当用户登录时使应用程序可以验证安全戳。
    11                     // 这是一项安全功能,当你更改密码或者向帐户添加外部登录名时,将使用此功能。
    12                     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
    13                         validateInterval: TimeSpan.FromMinutes(30),
    14                         regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    15                 }
    16             });
 
 
 
所以如果你使用上述的中间件(使用其他的身份认证的组件也可能会存在重写401响应码的行为),那么就无法手动返回401响应码
 
如果需要手动返回401响应码,那么就需要在Asp.Net的生命周期中对相应做一些修改,查阅MSDN的资料可以看到PreSendRequestHeaders事件中比较适合做这个操作。
 
 
在Global中我们添加如下方法,在PreSendRequestHeaders事件中插入我们自己的代码,将响应码设置为我们预期想要的值
  1.  1         public void Application_PreSendRequestHeaders(object sender, EventArgs e)
     2         {
     3             //处理401响应被多个框架重写的问题
     4             var values = Response.Headers.GetValues(ForceHttpStatusCodeResult.ForceHttpUnauthorizedHeaderName);
     5             if (values != null && values.Contains(ForceHttpStatusCodeResult.ForceHttpUnauthorizedHeaderValue))
     6             {
     7                 Response.ClearHeaders();
     8                 Response.StatusCode = (int)HttpStatusCode.Unauthorized;
     9             }
    10         }
 
 
由于请求到这里的时候,响应码已经被重写,所以我们通过一个自定义的请求头来标识当前请求是一个要被手动发送给客户端的401响应
 
 1     /// <summary>
 2     /// 强制返回指定的响应码
 3     /// 401响应码会被MVC框架和OWIN授权认证的中间件给重写
 4     /// </summary>
 5     public class ForceHttpStatusCodeResult : HttpStatusCodeResult
 6     {
 7 
 8         public const string ForceHttpUnauthorizedHeaderName = "ForceHttpUnauthorizedHeader";
 9         public const string ForceHttpUnauthorizedHeaderValue = "true";
10 
11         public ForceHttpStatusCodeResult(int state)
12             : this(state, "")
13         { }
14 
15         public ForceHttpStatusCodeResult(int state, string statusDescription)
16             : base(state, statusDescription)
17         {
18             if (state == (int)HttpStatusCode.Unauthorized)
19             {
20                 SetForceHttpUnauthorizedHeader();
21             }
22         }
23 
24 
25         private void SetForceHttpUnauthorizedHeader()
26         {
27             System.Web.HttpContext.Current.Response.AddHeader(ForceHttpUnauthorizedHeaderName, ForceHttpUnauthorizedHeaderValue);
28         }
29     }

 

 
 
此时我们在Action中就可以返回我们需要的任意响应码了
  1. 1         public ActionResult UnauthorizedAccess()
    2         {
    3             return new ForceHttpStatusCodeResult((int)HttpStatusCode.Unauthorized);
    4         }
 
Ajax请求结果:
 
 
 
下载:
   示例代码
 
 
参考资料:
 
 
 
posted @ 2016-01-07 16:00  陌上荼靡  阅读(4513)  评论(0编辑  收藏  举报