11

我正在這使窗體身份驗證ASP.NET MVC5項目。項目目前正處於測試階段,並且在Azure在線託管,但項目業主想禁用對網站的所有公衆訪問(因爲網站的某些部分不要求用戶在所有驗證)。ASP.NET MVC5基本HTTP認證和AntiForgeryToken例外

對於這個測試階段,我們決定實現基本的HTTP認證,從這個link。我已經改變了代碼,因此它更適合我的需求:

public class BasicAuthenticationAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    public string BasicRealm { get; set; } 

    protected string Username { get; set; } 
    protected string Password { get; set; } 

    public BasicAuthenticationAttribute(string username, string password) 
    { 
     this.Username = username; 
     this.Password = password; 
    } 

    public void OnAuthorization (AuthorizationContext filterContext) 
    { 
     var req = filterContext.HttpContext.Request; 
     var auth = req.Headers["Authorization"]; 
     if (!String.IsNullOrEmpty(auth)) 
     { 
      var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':'); 
      var user = new { Name = cred[0], Pass = cred[1] }; 

      if (user.Name == Username && user.Pass == Password) 
       return; 
     } 

     var res = filterContext.HttpContext.Response; 
     var alreadySent = HttpContext.Current.Items.Contains("headers-sent"); 

     if (!alreadySent) 
     { 
      res = filterContext.HttpContext.Response; 
      res.StatusCode = 401; 
      res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 

     } 
    } 
} 

我也把它註冊爲一個全球性的過濾器:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new HandleErrorExtendedAttribute()); 
     filters.Add(new BasicAuthenticationAttribute(AppConfig.BasicUsername, AppConfig.BasicPassword)); 
    } 
} 

然而,也有一些問題,當我運行該項目。如果我使用這個版本的代碼:

 if (!alreadySent) 
     { 
      res = filterContext.HttpContext.Response; 
      res.StatusCode = 401; 
      res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 
     } 

成功登錄後,它不斷重定向到表單登錄頁面。

但是如果我追加

res.End(); 

res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 

Antiforgerytoken在CSHTML文件拋出System.Web.HttpException

服務器不能追加頭後HTTP標頭已發送。

但是在這種情況下,它最終成功地進行了身份驗證。

我目前停留在這一點,不知道如何解決這個問題,因爲關閉窗體身份驗證是不是和選項,我不能刪除所有AntiForgeryTokens及其驗證。

+2

爲什麼會選擇這種方式?如果你想構建一個自定義的'Authentication Filter',你應該從'AuthorizeAttribute'繼承,重寫'IsAuthorized'函數,返回'false'給未授權的請求,並在'HandleUnauthorizedRequest'函數中處理它們。 – AnhTriet

+0

如果你用res.AppendHeader行翻轉res.StatusCode行會發生什麼? StatusCode值是否作爲「Body」的一部分計數,以便關閉Headers以不再被寫入?請考慮Andrew的迴應。 –

+0

PLZ不使用基本身份驗證。請注意,您提到的其他問題就像6歲,即使如此,也有更好的選擇。參見:http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/ – nothingisnecessary

回答

1

你試過res.AppendHeader之前這條線(..)?

Response.ClearHeaders(); 
3

我會建議你使用ASP.NET身份成員資格提供,因爲它包含在MVC 5.利用這一點,你可以簡單地驗證用戶無需編寫大量的代碼,因爲它是與以前的成員。它也可以使用外部登錄和內部cookie,就像使用FormsAuthentication方法一樣。您所需要的只是在代碼中進行簡單的配置,而無需編寫自定義過濾器。

1

而是與req.End()結束的要求,我想你想設置filterContext.Result,如下圖所示。結果設置到一個非空值將中斷MVC管道的其餘部分的處理,並導致響應被髮送給瀏覽器,但它不應該密封響應,End()做,所以你不應該得到的異常關於標題已被髮送。

試試這個:

filterContext.Result = new HttpUnauthorizedResult();