2

私はMVC3を初めて使用します。私は以下を達成するための提案を求めています:

  1. MVC3サイトでWindows認証が有効になっています。
  2. Oracle DBには、ロール情報を含む個別のUserProfileテーブルがあります。
  3. ユーザーは複数の製品を関連付けることができます。製品ごとに、ユーザーの役割は異なります。

必要:

  1. ユーザーが認証されたらすぐに、現在選択されている製品のアプリケーション固有の詳細をDBから取得したいと思います。私はRoleProviderによってこれを行うことができると思います。
  2. この情報をUserオブジェクトに追加したいと思います。どうすればよいですか?
  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 にシリアル化しています。Web サイトで 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 でラップします。これは、アプリケーションのどの部分からでもデータにアクセスできるように、プリンシパル オブジェクトにデータを保持するために必要です。WINDOWS プリンシパル オブジェクトをラップするために Application_AuthenticateRequest を使用しないでください。ロール プロバイダーを有効にすると、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 認証と組み合わせて追加のユーザー データを保存しようとしている人に役立つことを願っています。

目標を達成するためのより良いアプローチがあれば教えてください。

于 2012-06-29T05:47:04.210 に答える
1

カスタム プリンシパルと ID を使用して、追加のデータをユーザーに添付できます。カスタム メンバーシップ プロバイダーを使用すると、認証時にデータベースからデータを読み込むことができます。製品の変更をいつ行うかは、現在のスレッドからユーザーを取得でき、たとえばUser.UpdateProducts()カスタム ID に記述したメソッドを呼び出すことができます。

ここに例があります

VB での本格的な例

于 2012-06-28T13:42:52.523 に答える