MVC 3 Windows身份验证和其他用户数据

时间:2012-06-28 06:01:03

标签: asp.net-mvc-3 razor windows-authentication

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

  1. 我的MVC3网站已启用Windows身份验证。
  2. 我在Oracle DB中有单独的UserProfile表,它将包含角色 信息。
  3. 用户可以关联多个产品。对于用户的每个产品角色各不相同。
  4. 需要:

    1. 一旦用户通过身份验证,我就想获取应用程序 来自DB的当前所选产品的具体细节。我可以 这是我猜的RoleProvider。
    2. 我想将此信息附加到User对象。我该怎么做?
    3. 如果用户更改了产品,我应该可以将其他信息重置为User对象。可能吗?我该怎么办?
    4. 由于 阿伦

2 个答案:

答案 0 :(得分: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主要对象。如果您启用角色提供程序,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身份验证结合使用的人有所帮助。

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

答案 1 :(得分:1)

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

这是Example

Full blown example in VB