需求:
在默認創建的
Asp.Net MVC項目中(這里使用VS2013),需要手動返回一個401響應碼給瀏覽器。我們的代碼可能是下面這樣子的。
-
1 public ActionResult UnauthorizedAccess() 2 { 3 return new HttpStatusCodeResult((int)HttpStatusCode.Unauthorized); 4 }
實際的效果卻和預期的不太一樣,如果我們是通過地址欄直接訪問這個Action,可以看到請求被重定向到登錄頁面了

如果通過Ajax的方式進行訪問,可以看到直接返回了一個200的響應碼

因為當前創建的MVC項目默認使用的是一個叫CookieAuthentication的OWIN中間件來實現身份認證的功能的,該中間件中會將401響應碼進行特殊處理,所以導致我們無法手動返回401響應碼。
Startup類中的代碼:
-
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 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 public ActionResult UnauthorizedAccess() 2 { 3 return new ForceHttpStatusCodeResult((int)HttpStatusCode.Unauthorized); 4 }
Ajax請求結果:


下載:
參考資料: