ASP.NET MVC - カスタム IIdentity または IPrincipal を設定する 質問する

ASP.NET MVC - カスタム IIdentity または IPrincipal を設定する 質問する

かなり単純なことをする必要があります。ASP.NET MVC アプリケーションで、カスタムの IIdentity / IPrincipal を設定します。どちらが簡単か、より適切か。 および のようなものを呼び出せるように、デフォルトを拡張します。User.Identity.Id特別User.Identity.Roleなことは何もなく、いくつかの追加プロパティがあるだけです。

たくさんの記事や質問を読みましたが、実際よりも難しくしている気がします。簡単だと思っていました。ユーザーがログオンしたら、カスタム IIdentity を設定したいのです。そこで、Application_PostAuthenticateRequestglobal.asax に実装しようと思いました。しかし、これはすべてのリクエストで呼び出され、すべてのリクエストでデータベースへの呼び出しを行いたくありません。データベースからすべてのデータを要求し、カスタム IPrincipal オブジェクトに配置することになります。これも非常に不必要で、遅く、間違った場所 (そこでデータベース呼び出しを行う) にあるように思えますが、私が間違っている可能性があります。あるいは、そのデータは他にどこから来るのでしょうか?

そこで、ユーザーがログインするたびに、セッションに必要な変数をいくつか追加し、それをApplication_PostAuthenticateRequestイベント ハンドラーのカスタム IIdentity に追加できると考えました。ただし、my はそこにContext.Sessionあるnullため、これも適切な方法ではありません。

私はこれに 1 日取り組んできましたが、何かが足りない気がします。これはそれほど難しいことではないはずですよね? また、これに付随する (半) 関連のものすべてに少し混乱しています。、、、、、、、、MembershipProvider...。これらすべてが非常に混乱していると思うのは私だけでしょうか?MembershipUserRoleProviderProfileProviderIPrincipalIIdentityFormsAuthentication

誰かが、余分な煩わしさなしに IIdentity に追加データを格納するためのシンプルでエレガント、かつ効率的なソリューションを教えてくれたら、それは素晴らしいことです。SO に同様の質問があることは知っていますが、必要な答えがそこにあったら、私は見落としているに違いありません。

ベストアンサー1

やり方は次のとおりです。

IIdentity と IPrincipal の両方を実装する必要がなくなるため、IIdentity の代わりに IPrincipal を使用することにしました。

  1. インターフェースを作成する

    interface ICustomPrincipal : IPrincipal
    {
        int Id { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
    
  2. カスタムプリンシパル

    public class CustomPrincipal : ICustomPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
  3. CustomPrincipalSerializeModel - FormsAuthenticationTicket オブジェクトの userdata フィールドにカスタム情報をシリアル化します。

    public class CustomPrincipalSerializeModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
  4. LogIn メソッド - カスタム情報を含む Cookie の設定

    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
        serializeModel.Id = user.Id;
        serializeModel.FirstName = user.FirstName;
        serializeModel.LastName = user.LastName;
    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
    
        string userData = serializer.Serialize(serializeModel);
    
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                 1,
                 viewModel.Email,
                 DateTime.Now,
                 DateTime.Now.AddMinutes(15),
                 false,
                 userData);
    
        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);
    
        return RedirectToAction("Index", "Home");
    }
    
  5. Global.asax.cs - クッキーを読み取り、HttpContext.User オブジェクトを置き換えます。これは PostAuthenticateRequest をオーバーライドすることで行われます。

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
    
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.Id = serializeModel.Id;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
    
  6. Razor ビューでのアクセス

    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)
    

コードでは次のようになります:

    (User as CustomPrincipal).Id
    (User as CustomPrincipal).FirstName
    (User as CustomPrincipal).LastName

コードは一目瞭然だと思います。そうでない場合はお知らせください。

さらに、アクセスをさらに簡単にするために、ベース コントローラーを作成し、返された User オブジェクト (HttpContext.User) をオーバーライドすることもできます。

public class BaseController : Controller
{
    protected virtual new CustomPrincipal User
    {
        get { return HttpContext.User as CustomPrincipal; }
    }
}

そして、各コントローラーに対して次の操作を実行します。

public class AccountController : BaseController
{
    // ...
}

これにより、次のようなコードでカスタム フィールドにアクセスできるようになります。

User.Id
User.FirstName
User.LastName

しかし、これはビュー内では機能しません。そのためには、カスタム WebViewPage 実装を作成する必要があります。

public abstract class BaseViewPage : WebViewPage
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

Views/web.config でこれをデフォルトのページ タイプにします。

<pages pageBaseType="Your.Namespace.BaseViewPage">
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />
  </namespaces>
</pages>

ビューでは次のようにアクセスできます。

@User.FirstName
@User.LastName

おすすめ記事