2012-02-22 67 views
5

我有一個使用基本身份驗證的ASP MVC3 restful服務。搜索堆棧溢出後,我創建了以下代碼。asp mvc 3 ActionFilter用於基本身份驗證

public class BasicAuthentication : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var req = filterContext.HttpContext.Request; 
     if (String.IsNullOrEmpty(req.Headers["Authorization"])) 
     { 
      filterContext.Result = new HttpNotFoundResult(); 
     } 
     else 
     { 
      var credentials = System.Text.ASCIIEncoding.ASCII 
         .GetString(Convert.FromBase64String(req.Headers["Authorization"].Substring(6))) 
         .Split(':'); 
      var user = new { Name = credentials[0], Password = credentials[1] }; 
      if(!(user.Name == "username" && user.Password == "passwords")) 
      { 
       filterContext.Result = new HttpNotFoundResult(); 
      } 
     } 
    } 
} 

1)ActionFilterAttribute是最好的方法嗎?

2)是否設置了filterContext.Result拒絕訪問控制器方法的正確方法?

3)有什麼我做錯了嗎?

謝謝。

-Nick

+0

您使用基本與基本型(二級AUTH)的形式/自定義類型AUTH或仍使用域帳戶? – 2012-02-22 17:16:58

回答

12

1)是一個ActionFilterAttribute做到這一點的最好方法是什麼?
我這麼認爲。這種方法反映了內置Authorize屬性的實現。

2)是否設置filterContext.Result拒絕訪問控制器方法的正確方法?
是的。多數民衆贊成在那裏。 (1)

3)有什麼我做錯了嗎?

  • 您認爲授權頭的內容是在 正確的格式和正確的編碼。
  • 您認爲該請求用於基本認證,而不是其他認證方案。
  • 我傾向於使用HttpUnauthorizedResult()通過HttpNotFoundResult()發送http 401錯誤而不是http 404錯誤。

下面是我的代碼實現(我肯定也有它的問題)。

public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     try 
     { 
      if (String.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"])) 
      { 
       filterContext.Result = new HttpUnauthorizedResult(); 
      } 
      else 
      { 
       if (filterContext.HttpContext.Request.Headers["Authorization"].StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase)) 
       { 
        string[] credentials = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(filterContext.HttpContext.Request.Headers["Authorization"].Substring(6))).Split(':'); 

        if (credentials.Length == 2) 
        { 
         if (String.IsNullOrEmpty(credentials[0])) 
         { 
          filterContext.Result = new HttpUnauthorizedResult(); 
         } 
         else if (!(credentials[0] == "username" && credentials[1] == "passwords")) 
         { 
          filterContext.Result = new HttpUnauthorizedResult(); 
         } 
        } 
        else 
        { 
         filterContext.Result = new HttpUnauthorizedResult(); 
        } 
       } 
       else 
       { 
        filterContext.Result = new HttpUnauthorizedResult(); 
       } 
      } 

      base.OnActionExecuting(filterContext); 
     } 
     catch 
     { 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

注意

  • 我沒有將用戶名和密碼,非法字符檢查。
  • 我無法解決如何實現異常處理,所以我已經很簡單。

參考

(1)http://msdn.microsoft.com/en-us/magazine/gg232768.aspx

-2

1)不,ActionFilter屬性不是認證用戶一個不錯的辦法。 (因爲我們需要進行一次認證,並設置身份驗證Cookie,所以直到HttpContext.User中cookie過期將繼續驗證)

2)是的,設置filtercontext.Result是爲了防止訪問的理想方式。 (但不是分配HttpNotFoundResult,使用RedirectResult重定向到登錄頁面)

3)我真的不明白爲什麼有這樣的授權實現。 最好的辦法是做一個能接收表單發佈數據(用戶名和密碼)的操作。並使用Authorize屬性來防止未經授權的訪問。

以下是VS2010中默認MVC3示例應用程序的代碼。

[HttpPost] 
    public ActionResult LogOn(LogOnModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
      if (Membership.ValidateUser(model.UserName, model.Password)) 
      { 
       FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); 
       if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") 
        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
       { 
        return Redirect(returnUrl); 
       } 
       else 
       { 
        return RedirectToAction("Index", "Home"); 
       } 
      } 
      else 
      { 
       ModelState.AddModelError("", "The user name or password provided is incorrect."); 
      } 
     } 

     // If we got this far, something failed, redisplay form 
     return View(model); 
    } 
+0

我瞭解表單登錄模型,並將其用於普通網站。這是如何工作的一個寧靜的服務?用戶如何提供登錄? – Nikhil 2012-02-22 19:07:02

+0

MVC仍然使用表單身份驗證。您尋找一些系統/服務將調用mvc uri,傳遞網絡憑證。如果是這樣,上面的方法看起來不錯(但是更好的是你可以使用BaseController並從它繼承所有的子控制器。然後你可以在OnActionExecuting方法中編寫與上面相同的代碼,**除非不是所有的代碼都是由API調用的** ) – Manas 2012-02-23 04:19:35

+2

我認爲你在回答問題時忽略了「服務」和「基本認證」等字樣。 – humblelistener 2012-11-08 18:41:50

8

重構的版本阿德里安的

public class BasicAuthenticationAttribute : ActionFilterAttribute 
{ 
    private static readonly string AuthorizationHeader = "Authorization"; 
    private static readonly string BasicHeader = "Basic "; 
    private static readonly string Username = "username"; 
    private static readonly string Password = "password"; 
    private static readonly char[] Separator = ":".ToCharArray(); 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     try 
     { 
      if (!Authenticated(filterContext.HttpContext.Request)) 
       filterContext.Result = new HttpUnauthorizedResult(); 

      base.OnActionExecuting(filterContext); 
     } 
     catch 
     { 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

    private bool Authenticated(HttpRequestBase httpRequestBase) 
    { 
     bool authenticated = false; 

     if (String.IsNullOrEmpty(httpRequestBase.Headers[AuthorizationHeader]) == false && 
      httpRequestBase.Headers[AuthorizationHeader].StartsWith(BasicHeader, StringComparison.InvariantCultureIgnoreCase)) 
     { 
      string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(
       httpRequestBase.Headers[AuthorizationHeader].Substring(BasicHeader.Length))).Split(Separator); 

      if (credentials.Length == 2 && credentials[0] == Username && credentials[1] == Password) 
      { 
       authenticated = true; 
      } 
     } 

     return authenticated; 
    } 
} 
+1

+1的時間和精力。很有用。但是,如果第一個條件是「不」認證,那麼引發HttpUnauthorisedResult。 – fluent 2013-05-15 15:00:10