2014-03-03 30 views
1

我在我的MVC應用程序中使用窗體身份驗證。這工作正常。但是,我不想調整授權,只允許某些角色的人員。登錄對應於活動目錄中的用戶,角色對應於用戶所在的組。使用窗體身份驗證的角色

對於身份驗證,我只需在驗證登錄名後調用FormsAuthentication.SetAuthCookie(username,true)即可​​。

授權,我第一次應用的屬性我想,以確保

[Authorize(Roles = "AllowedUsers")] 
public class MyController 
... 

接下來的控制器,我在處理Global.asax中OnAuthenticate事件。

protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs args) 
{ 
    if (FormsAuthentication.CookiesSupported) 
     { 
      if (Request.Cookies[FormsAuthentication.FormsCookieName] != null) 
      { 
       try 
       { 
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
        Request.Cookies[FormsAuthentication.FormsCookieName].Value); 

        // Create WindowsPrincipal from username. This adds active directory 
        // group memberships as roles to the user. 
        args.User = new WindowsPrincipal(new WindowsIdentity(ticket.Name)); 

        FormsAuthentication.SetAuthCookie(ticket.Name, true); 
       } 
       catch (Exception e) 
       { 
        // Decrypt method failed. 
       } 
     } 
    } 
    else 
    { 
     throw new HttpException("Cookieless Forms Authentication is not " + "supported for this application."); 
    } 
} 

有了這個當有人訪問網站,他們得到登錄屏幕。從那裏他們實際上可以登錄。但是,不知何故,它不保存auth cookie,他們在點擊下一個鏈接後獲得登錄屏幕。我嘗試在OnAuthenticate()中添加對SetAuthCookie()的調用,但它們沒有任何區別。

在我添加此事件處理程序來處理授權之前,身份驗證正常工作。因此,框架中的用戶正在設置。我想知道這是否正確的做法,我只是錯過了一些東西,或者如果我需要一種不同的方法。

我需要做些什麼才能使其發揮作用?

感謝, 斯科特

+1

您是否嘗試過轉儲當前用戶所在的組/聲明列表?我懷疑他們在那裏,但作爲AD組SID不是組名。 – 0leg

回答

1

好像我最初的做法是行不通的。我試圖讓ASP.NET從他們的AD帳戶中自動加載用戶角色。沒有評論這是否可能。然而,我所做的研究表明,我必須編寫代碼將AD組成員加載到用戶角色中。

創建ASP.NET MVC使用的用戶主體的解決方案似乎是在FormsAuthentication_OnAuthenticate()中創建它並將其分配給Context.User。看起來如果我沒有設置Context.User ASP.NET MVC根據FormsAuthentication_OnAuthenticate()返回後的驗證票據創建一個用戶主體。另外,如果我將它設置在FormsAuthentication_OnAuthenticate()中,ASP.NET MVC似乎對Context.User不起作用。

以下是我最終做的。

這是處理認證

public ActionResult LogOn(FormCollection collection, string returnUrl) 
{ 
    // Code that authenticates user against active directory 
    if (authenticated) 
    { 
     var authTicket = new FormsAuthenticationTicket(username, true, 20); 

     string encryptedTicket = FormsAuthentication.Encrypt(authTicket); 

     var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); 
     authCookie.Expires = DateTime.Now.AddMinutes(30); 
     Response.Cookies.Add(authCookie); 

     if (Url.IsLocalUrl(returnUrl) 
      && returnUrl.Length > 1 
      && returnUrl.StartsWith("/", StringComparison.OrdinalIgnoreCase) 
      && !returnUrl.StartsWith("//", StringComparison.OrdinalIgnoreCase) 
      && !returnUrl.StartsWith("/\\", StringComparison.OrdinalIgnoreCase)) 
     { 
      return Redirect(returnUrl); 
     } 
     else 
     { 
      return Redirect("~/"); 
     } 
    } 
    return View(); 
} 

我最初嘗試只是打電話FormsAuthentication.SetAuthCookie(用戶名,真實),而不是手動創建,加密,並將其添加到響應的cookie集合的代碼。這在開發環境中起作用。但是,這並沒有在我發佈到網站後。

這是註銷代碼

public ActionResult LogOff() 
{ 
    var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; 
    if (authCookie != null) 
    { 
     authCookie.Expires = DateTime.Today.AddDays(-1); 
    } 

    Response.Cookies.Add(authCookie); 
    FormsAuthentication.SignOut(); 

    return RedirectToAction("Index", "Home"); 
} 

FormsAuthentication.SignOut()似乎並沒有做任何事情,我切換到手動創建,加密,並在加入身份驗證票響應Cookie集合後登錄代碼。所以我必須手動過期cookie。

這是我的代碼有FormsAuthentication_OnAuthenticate()

protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs args) 
{ 
    HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName]; 
    if (authCookie == null || string.IsNullOrWhiteSpace(authCookie.Value)) 
     return; 

    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); 

    UserData userData = null; 
    if (Application["UserData_" + authTicket.Name] == null) 
    { 
     userData = new UserData(authTicket.Name); 
     Application["UserData_" + authTicket.Name] = userData; 
    } 
    else 
    { 
     userData = (UserData)Application["UserData_" + authTicket.Name]; 
    } 

    Context.User = new GenericPrincipal(new GenericIdentity(authTicket.Name), userData.Roles); 
} 

的UserData是我創建的用於處理高速緩存用戶角色的類。這是因爲活動目錄返回用戶所屬的組成員身份所花費的時間。爲了完整性,以下是我擁有的UserData代碼。

public class UserData 
{ 
    private int _TimeoutInMinutes; 
    private string[] _Roles = null; 

    public string UserName { get; private set; } 
    public DateTime Expires { get; private set; } 
    public bool Expired { get { return Expires < DateTime.Now; } } 
    public string[] Roles 
    { 
     get 
     { 
      if (Expired || _Roles == null) 
      { 
       _Roles = GetADContainingGroups(UserName).ToArray(); 
       Expires = DateTime.Now.AddMinutes(_TimeoutInMinutes); 
      } 
      return _Roles; 
     } 
    } 

    public UserData(string userName, int timeoutInMinutes = 20) 
    { 
     UserName = userName; 
     _TimeoutInMinutes = timeoutInMinutes; 
    } 
} 
0

角色也可以存儲在cookie中,你至少有兩個選項:

  • 一個角色提供的cookie(支持形式餅乾另一餅乾),設置cacheRolesInCookie="true"在角色提供者配置web.config。角色在首次授權模塊要求角色併發布cookie時讀取

  • 將角色存儲在表單cookie的userdata部分中的自定義角色提供程序必須將角色添加到角色的用戶數據部分形式使用網站手動

Authorization模塊詢問用戶角色,其中,如果角色提供啓用當前主體,無論是掃描角色的cookie(第一個選項)或觸發的自定義角色提供方法。

另一種推薦的方法是切換到可以替換表單身份驗證的會話身份驗證模塊(SAM)。有一些重要的優點,包括SAM再現ClaimsPrincipal出的cookie和角色只是Role索賠的事實:

// create cookie 

SessionAuthenticationModule sam = 
    (SessionAuthenticationModule) 
    this.Context.ApplicationInstance.Modules["SessionAuthenticationModule"]; 

ClaimsPrincipal principal = 
    new ClaimsPrincipal(new GenericPrincipal(new GenericIdentity("username"), null)); 

// create any userdata you want. by creating custom types of claims you can have 
// an arbitrary number of your own types of custom data 
principal.Identities[0].Claims.Add(new Claim(ClaimTypes.Role, "role1")); 
principal.Identities[0].Claims.Add(new Claim(ClaimTypes.Role, "role2")); 

var token = 
    sam.CreateSessionSecurityToken( 
     principal, null, DateTime.Now, DateTime.Now.AddMinutes(20), false); 
sam.WriteSessionTokenToCookie(token); 

從現在起,身份被存儲在cookie中,並自動管理,是的,在Authorization您的控制器上的屬性按預期工作。

瞭解更多關於我的博客上與SAM替換形式的模塊:

http://www.wiktorzychla.com/2012/09/forms-authentication-revisited.html

+0

抱歉,延遲響應。東西出現在工作中。無論如何,有趣的理想。但是,我不喜歡在cookie中緩存用戶角色的想法。用戶不可能修改cookies的內容並給自己任何他們想要的角色? ASP.NET身份驗證Cookie已加密,或者可能只是基於64位編碼。所以這並不容易。不過我想我會將其緩存在應用程序變量或數據庫中。這也將保持發送/發送的數據量最小化。 –

+0

驗證Cookie **總是**加密。 –