【问题标题】:MVC 3 Windows Authentication and Additional User DataMVC 3 Windows 身份验证和其他用户数据
【发布时间】:2012-06-29 15:08:48
【问题描述】:

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

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

需要:

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

谢谢 阿伦

【问题讨论】:

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


【解决方案1】:

我只是发布我尝试过的代码。这只是我采取的一种方法。但是我需要 epxperts cmets 来说明这在安全性、性能等方面是否是个好主意。

第 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 身份验证相关的其他用户数据的人有所帮助。

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

【讨论】:

    【解决方案2】:

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

    这是Example

    Full blown example in VB

    【讨论】:

    • 感谢您的回复。这有助于我解决我的问题。我最终将 FormsAuthenticationTicket 与 WindowsAuthenticatioin 混合在一起。
    猜你喜欢
    • 2013-07-26
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    • 2011-11-09
    • 1970-01-01
    相关资源
    最近更新 更多