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

Aru*_*run 2 windows-authentication razor asp.net-mvc-3

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

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

需要:

  1. 一旦用户通过身份验证,我就想从DB获取当前所选产品的应用程序特定详细信息.我可以通过RoleProvider来做到这一点.
  2. 我想将此信息附加到User对象.我该怎么做呢?
  3. 如果用户更改了产品,我应该能够将其他信息重置为User对象.可能吗?我该怎么做?

谢谢阿伦

Aru*_*run 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; }
    }
Run Code Online (Sandbox Code Playgroud)

第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
    }
Run Code Online (Sandbox Code Playgroud)

第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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

第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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

步骤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;
        }
Run Code Online (Sandbox Code Playgroud)

正如Preben建议的那样,每当用户切换到不同的产品时,我都会更新cookie.

希望这对于愿意将其他用户数据与Windows身份验证结合使用的人有所帮助.

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