2012-06-28 52 views
2

我是MVC3的新手。我正在尋求建議實現如下:MVC 3 Windows身份驗證和其他用戶數據

  1. 我的MVC3網站已啓用Windows身份驗證。
  2. 我在Oracle DB中有單獨的UserProfile表,它將包含角色 信息。
  3. 用戶可以關聯多個產品。對於用戶的每個產品角色都有所不同。

極品:

  1. 一旦用戶通過驗證後,我希望獲取從DB應用 具體細節當前所選的產品。我猜可以通過RoleProvider做 。
  2. 我想將此信息附加到用戶對象。我該怎麼做呢?
  3. 如果用戶更改產品,我應該可以重置用戶對象的附加信息。可能嗎?我該怎麼做?

感謝 阿倫

+0

告訴我們一些代碼 – TRR

+1

[你有什麼試過](http://mattgemmell.com/2008/12/08/what-have-you-tried/)? –

回答

1

你可以使用自定義用戶和身份額外數據附加到你的用戶。使用自定義成員資格提供程序,您可以從身份驗證數據庫加載數據。 何時產品更改可以從當前線程獲取用戶,您可以調用例如您在自定義標識上編寫的方法User.UpdateProducts()

這裏是一個Example

Full blown example in VB

+0

感謝您的回覆。這有助於我解決我的問題。我最終混合了FormsAuthenticationTicket和WindowsAuthenticatioin。 – Arun

5

我只是發表我已經嘗試了代碼。這只是我採取的一種方法。但我需要epxperts評論說這是好主意或沒有對於安全性,性能等

第1步:定義自定義接口它繼承的IPrincipal

public interface ICustomPrincipal : IPrincipal 
    { 
     string[] Roles { get; set; } 
     string Country { get; set; } 
     string Region { get; set; } 
     string Department { get; set; } 
     string CurrentProductId { get; set; } 
     bool HasAcceptedTerms { get; set; } 
    } 

第2步:使用以上實現自定義主界面

public class CustomPrincipal : ICustomPrincipal 
    { 
     private IPrincipal principal; 

     public CustomPrincipal(IPrincipal principal, WindowsIdentity identity) 
     { 
      this.Identity = identity; 
      this.principal = principal; 
     } 

     #region IPrincipal Members 

     public IIdentity Identity { get; private set; } 

     public bool IsInRole(string role) 
     { 
      return (principal.IsInRole(role)); 
     } 

     public string Department { get; set; } 

     public string[] Roles { get; set; } 

     public string Country { get; set; } 

     public string Region { get; set; } 

     public string CurrentProductId { get; set; } 

     public bool HasAcceptedTerms { get; set; } 

     #endregion 
    } 

第3步:定義您自己的角色提供程序。也使該供應商的web.config文件條目並將其設置爲默認提供

public class MyCustomRoleProvider : RoleProvider 
    { 
     List<string> _roles = new List<string> { "System Administrators", "Product Administrators", "Users", "Guests" }; 

     public override string[] GetRolesForUser(string username) 
     { 

      //TODO: Get the roles from DB/Any other repository and add it to the list and return as array 
      return _roles.ToArray(); 
     } 

     public override bool IsUserInRole(string username, string roleName) 
     { 
      if (_roles.Contains(roleName)) 
      { 
       //this.Department = "My Department"; 
       return true; 
      } 
      else 
       return false; 
     } 


     public override void AddUsersToRoles(string[] usernames, string[] roleNames) 
     { 
      throw new NotImplementedException(); 
     } 

     public override string ApplicationName 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public override void CreateRole(string roleName) 
     { 
      throw new NotImplementedException(); 
     } 

     public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) 
     { 
      throw new NotImplementedException(); 
     } 

     public override string[] FindUsersInRole(string roleName, string usernameToMatch) 
     { 
      throw new NotImplementedException(); 
     } 

     public override string[] GetAllRoles() 
     { 
      throw new NotImplementedException(); 
     } 

     public override string[] GetUsersInRole(string roleName) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) 
     { 
      throw new NotImplementedException(); 
     } 

     public override bool RoleExists(string roleName) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

第4步:下面實現事件

注:我serialzing其他用戶信息到的FormsAuthenticationTicket。我的網站已啓用Windows身份驗證。

protected void WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e) 
     { 
      if (null == Request.Cookies.Get("authCookie")) 
      { 
       var userId = e.Identity.Name; 
       //TODO: You may need to get the user details like country, region etc. from DB. For simplicity, I have just assigned user roles (multiple) property 

       //Instead of string array, you should use your own Class to hold this custom data and then serialize 
       string[] userRoles = new string[] { "System Administrators", "Users" }; 

       StringWriter writer = new StringWriter(); 
       XmlSerializer xs = new XmlSerializer(typeof(string[])); 
       xs.Serialize(writer, userRoles); 

       FormsAuthenticationTicket formsAuthTicket = 
        new FormsAuthenticationTicket(
           1, 
           userId, 
           DateTime.Now, 
           DateTime.Now.AddMinutes(20), 
           false, 
           writer.ToString()); 

       var encryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket); 

       HttpCookie httpCookie = new HttpCookie("authCookie", encryptedTicket); 

       Response.Cookies.Add(httpCookie); 
      } 
     } 

第5步:使用PostAuthenticateRequest事件將您的RolePrincipal包裝到您的CustomPrincipal中。這對於將數據保存在Principal對象中是很有必要的,以便您可以在應用程序的任何部分訪問它。不要使用Application_AuthenticateRequest來覆蓋WINDOWS主體對象。如果您啓用了角色提供者,ASP。NET將實際上用角色主體來替換WINDOWS主體。

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e) 
     { 
      HttpCookie authCookie = Context.Request.Cookies.Get("authCookie"); 
      FormsAuthenticationTicket formsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value); 

      CustomPrincipal newUser = new CustomPrincipal(User, (WindowsIdentity)User.Identity); 

      StringReader sr = new StringReader(formsAuthenticationTicket.UserData); 
      XmlSerializer xs = new XmlSerializer(typeof(string[])); 

      object ret = xs.Deserialize(sr); 
      newUser.Roles = (string[]) ret; 
      Context.User = newUser; 
     } 

正如Preben所建議的那樣,每當用戶轉向不同的產品時,我都會更新cookie。

希望這有助於願意存儲更多用戶數據與Windows身份驗證相結合的用戶。

請讓我知道是否有更好的方法來實現目標。