2012-06-28 120 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身份验证相结合的用户。

请让我知道是否有更好的方法来实现目标。