2

我正在開發一個擁有多個角色的用戶的複雜網站。用戶還可以與數據庫中的其他項目結合使用,並與他們的角色一起定義他們可以在網站上看到和做的事情。現在Asp.net MVC讓用戶在角色之間切換

,一些用戶已經超過1層的作用,但該網站只能同時處理,因爲結構複雜1層的作用。

的想法是,在用戶登錄,並在該網站,他可以選擇他的一個角色拐角處的下拉菜單。如果他只有一個角色,那麼就沒有下拉。

現在我在DB的最後選擇的角色值存儲與用戶自己的其他設置。當他回來時,這種角色仍然被記住。

下拉的值應該是在整個網站的訪問。 我想做2件事:

  1. 將當前角色存儲在Session
  2. 重寫IsInRole方法或寫IsCurrentlyInRole方法來檢查所有進入當前選定的角色,而不是所有的角色一樣,原來IsInRole方法

對於會話的一部分存儲我想那會Global.asax

protected void Application_AuthenticateRequest(Object sender, EventArgs e) { 
     if (User != null && User.Identity.IsAuthenticated) { 
      //check for roles session. 
      if (Session["CurrentRole"] == null) { 
       NASDataContext _db = new NASDataContext(); 
       var userparams = _db.aspnet_Users.First(q => q.LoweredUserName == User.Identity.Name).UserParam; 
       if (userparams.US_HuidigeRol.HasValue) { 
        var role = userparams.aspnet_Role; 
        if (User.IsInRole(role.LoweredRoleName)) { 
         //safe 
         Session["CurrentRole"] = role.LoweredRoleName; 
        } else { 
         userparams.US_HuidigeRol = null; 
         _db.SubmitChanges(); 
        } 
       } else { 
        //no value 
        //check amount of roles 
        string[] roles = Roles.GetRolesForUser(userparams.aspnet_User.UserName); 
        if (roles.Length > 0) { 
         var role = _db.aspnet_Roles.First(q => q.LoweredRoleName == roles[0].ToLower()); 
         userparams.US_HuidigeRol = role.RoleId; 
         Session["CurrentRole"] = role.LoweredRoleName; 
        } 
       } 
      } 

     } 
    } 

但顯然這會導致運行時錯誤。 Session state is not available in this context.

  1. 我該如何解決這個問題,而這是真的 把這個 代碼的最佳地點?
  2. 如何擴展用戶(IPrincipal?)有IsCurrentlyInRole不失所有其他功能
  3. 也許我這樣做是完全錯誤的,有一個更好的方式來做到這一點?

任何幫助,非常感謝。

回答

3

是的,你不能在Application_AuthenticateRequest訪問會話。
我已經創建了我自己的CustomPrincipal。我會告訴你的例子是什麼我最近做:

public class CustomPrincipal: IPrincipal 
{ 
    public CustomPrincipal(IIdentity identity, string[] roles, string ActiveRole) 
    { 
     this.Identity = identity; 
     this.Roles = roles; 
     this.Code = code; 
    } 

    public IIdentity Identity 
    { 
     get; 
     private set; 
    } 

    public string ActiveRole 
    { 
     get; 
     private set; 
    } 

    public string[] Roles 
    { 
     get; 
     private set; 
    } 

    public string ExtendedName { get; set; } 

    // you can add your IsCurrentlyInRole 

    public bool IsInRole(string role) 
    { 
     return (Array.BinarySearch(this.Roles, role) >= 0 ? true : false); 
    } 
} 

我Application_AuthenticateRequest讀取cookie,如果有一個認證憑證(用戶登錄):

protected void Application_AuthenticateRequest(Object sender, EventArgs e) 
{ 
    HttpCookie authCookie = Request.Cookies[My.Application.FORMS_COOKIE_NAME]; 
    if ((authCookie != null) && (authCookie.Value != null)) 
    { 
     Context.User = Cookie.GetPrincipal(authCookie); 
    } 
} 


public class Cookie 
    { 
    public static IPrincipal GetPrincipal(HttpCookie authCookie) 
    { 
     FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
     if (authTicket != null) 
     { 
      string ActiveRole = ""; 
      string[] Roles = { "" }; 
      if ((authTicket.UserData != null) && (!String.IsNullOrEmpty(authTicket.UserData))) 
      { 
      // you have to parse the string and get the ActiveRole and Roles. 
      ActiveRole = authTicket.UserData.ToString(); 
      Roles = authTicket.UserData.ToString(); 
      } 
      var identity = new GenericIdentity(authTicket.Name, "FormAuthentication"); 
      var principal = new CustomPrincipal(identity, Roles, ActiveRole); 
      principal.ExtendedName = ExtendedName; 
      return (principal); 
     } 
     return (null); 
    } 
} 

我已經延長我的cookie添加身份驗證票證的UserData。我在這裏把額外的信息:

這是在登錄電子後創建的cookie功能:

public static bool Create(string Username, bool Persistent, HttpContext currentContext, string ActiveRole , string[] Groups) 
    { 
     string userData = ""; 

     // You can store your infos 
     userData = ActiveRole + "#" string.Join("|", Groups); 

     FormsAuthenticationTicket authTicket = 
      new FormsAuthenticationTicket(
      1,                // version 
      Username, 
      DateTime.Now,              // creation 
      DateTime.Now.AddMinutes(My.Application.COOKIE_PERSISTENCE),  // Expiration 
      Persistent,              // Persistent 
      userData);              // Additional informations 

     string encryptedTicket = System.Web.Security.FormsAuthentication.Encrypt(authTicket); 

     HttpCookie authCookie = new HttpCookie(My.Application.FORMS_COOKIE_NAME, encryptedTicket); 

     if (Persistent) 
     { 
      authCookie.Expires = authTicket.Expiration; 
      authCookie.Path = FormsAuthentication.FormsCookiePath; 
     } 

     currentContext.Response.Cookies.Add(authCookie); 

     return (true); 
    } 

現在你可以隨時隨地訪問您的相關信息在你的應用程序:

CustomPrincipal currentPrincipal = (CustomPrincipal)HttpContext.User; 

因此您可以訪問您的自定義主體成員:currentPrincipal.ActiveRole

當用戶更改它的角色(活動角色)時,您可以重寫cookie。

我忘了說我在authTicket.UserData中存儲了一個JSON序列化的類,所以它很容易反序列化和解析。

你可以找到更多的信息here

+0

非常有趣!我有點固定它與會議和所有,但我可能會使用部分代碼來改善它。我也覆蓋了`AuthorizeAttribute`會話會很快失去它的價值,這使得我需要每次檢查它並經常重新加載它。我會提出我的最終代碼,以便儘快查看。 – Stefanvds 2011-02-18 17:04:36

0

如果您真的希望用戶一次只有1個活動角色(如想要重寫IsInRole所暗示的那樣),也許最簡單的方法是將所有用戶的「潛在」角色存儲在單獨的位置,但實際上只允許它們一次處於1個ASP.NET身份驗證角色。當他們選擇一個新角色時,使用內置方法將他們從當前角色中移除並將其添加到新角色中。

+0

有趣的開箱思維。雖然它讓我擔心所有其他額外的代碼,我需要寫在管理面板中添加和管理角色的用戶... – Stefanvds 2011-02-17 15:35:44