2

我是 MVC3 的新手。我正在寻求实现以下目标的建议:

  1. 我的 MVC3 站点已启用 Windows 身份验证。
  2. 我在 Oracle DB 中有单独的 UserProfile 表,其中包含角色信息。
  3. 用户可以关联多个产品。对于用户的每个产品角色(S)有所不同。

需要:

  1. 用户通过身份验证后,我想从数据库中获取当前所选产品的特定于应用程序的详细信息。我猜我可以通过 RoleProvider 做到这一点。
  2. 我想将此信息附加到用户对象。我该怎么做呢?
  3. 如果用户更改产品,我应该能够将附加信息重置为 User 对象。是否可以?我该怎么做?

谢谢阿伦

4

2 回答 2

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 步:实施以下事件

注意:我将其他用户信息序列化到 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 主对象。如果启用 ROLE PROVIDER,ASP.NET 实际上将用 ROLE PRINCIPAL 替换 WINDOWS PRINCIPAL。

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 身份验证一起存储其他用户数据的人有所帮助。

如果有更好的方法来实现目标,请告诉我。

于 2012-06-29T05:47:04.210 回答
1

您可以使用自定义主体和身份将其他数据附加到您的用户。使用自定义成员资格提供程序,您可以在身份验证时从数据库加载数据。当产品更改时,您可以从当前线程中获取用户,并且您可以调用例如User.UpdateProducts()您在自定义身份上编写的方法。

这是一个例子

VB中的完整示例

于 2012-06-28T13:42:52.523 回答