いぇいいぇい

ASP.NET、PHPを中心に書いています

ASP.NET Identityでユーザーに紐付いた別テーブルの情報を、DBアクセスなしにページヘッダに表示する方法

契約情報があって、その下に複数のユーザーをぶら下げるという構成の場合。(契約情報=ユーザーとしてもいいんだろうけど、担当者の変更などを考えると複数ユーザーにできたほうがよいと思った。)

ユーザーテーブルに契約情報テーブルを関連付ける

まずASP.NET Identityでユーザーテーブルに契約情報テーブルを関連付けたい。

調べた結果ApplicationUserは普通のモデルクラスなのでCode Firstなら単純に関連テーブルとして定義してやればいい。

public enum SubscriptionKind
{
    Free = 0,
    Standard = 1,
}

public enum SubscriptionStatus
{
    Active = 0,
    Cancelled = 1,
}

public class Subscription
{
    public int ID { get; set; }

    public SubscriptionKind SubscriptionKind { get; set; }

    public SubscriptionStatus SubscriptionStatus { get; set; }
}

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public int SubscriptionId { get; set; }

    public virtual Subscription Subscription { get; set; }

    public DateTime CreatedDate { get; set; }
}

契約情報をクレームに追加する

さらに契約情報をページヘッダに表示したい。毎回DBアクセスしたくないのでクレーム用Cookieから読み込みたい。

public class ApplicationClaimTypes
{
    public const string SubscriptionKind = "http://mamemaki.com/claims/subscriptionkind";
    public const string SubscriptionStatus = "http://mamemaki.com/claims/subscriptionstatus";
}

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
    {
        // authenticationType が CookieAuthenticationOptions.AuthenticationType で定義されているものと一致している必要があります
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // ここにカスタム ユーザー クレームを追加します
        userIdentity.AddClaim(new Claim(ApplicationClaimTypes.SubscriptionKind, this.Subscription.SubscriptionKind.ToString()));
        userIdentity.AddClaim(new Claim(ApplicationClaimTypes.SubscriptionStatus, this.Subscription.SubscriptionStatus.ToString()));
        return userIdentity;
    }
}

GenerateUserIdentityAsync()でクレームを追加してやるといいらしい。他のタイミングじゃダメなんだろうか。。?

契約情報をページヘッダに表示する

これで_Layout.cshtmlなどからDBアクセスせずに契約情報を表示できた。

<li>契約種別: @Html.Raw(((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst(ApplicationClaimTypes.SubscriptionKind).Value)</li>

こりゃ便利ですな。