ASP.NET Identity のセキュリティスタンプ機能を使う

ASP.NET Identity に IUserSecurityStampStore というインタフェースがあるのですが、これをどうやって使うのか、そもそも何のためにあるのかも分からなかったので調べてみました。

そもそも ASP.NET Identity って何?というのは CodeZineASP.NET Identity入門 が非常に分かりやすいです。

UserStore が実装するインタフェース

ASP.NET Identity には拡張を容易にするためにたくさんのインタフェースがあります。

そのインタフェースも、責務によって大きくいくつかのカテゴリに分けられるのですが、UserStore という、ユーザ情報の CRUD を主な責務とするクラスが実装しているインタフェースが以下です。

  • IUserLoginStore
  • IUserClaimStore
  • IUserRoleStore
  • IUserPasswordStore
  • IUserSecurityStampStore
  • IUserStore
  • IDisposable

全体的に名前だけで何となく想像がついたんですが、IUserSecurityStampStore<TUser> だけが何なのか MSDN を見てもさっぱり分からず。。。

IUserSecurityStampStore の役割

stackoverflow に私と同じ疑問を持った方がいました。実装者に回答してもらっています。
What is ASP.NET Identity's IUserSecurityStampStore interface? - stackoverflow

あー、なるほどー。

どこからでも全てのログインセッションを無効化できるようにすることを目的とした、ログイン情報のスナップショットらしいです。 クッキーに、ログインに紐付くセキュリティスタンプとやらをを埋め込んでいるようですね。

例えば、ユーザがパスワードを変更したらその時点で即座に現在のログインセッション以外全てを無効にする用途に使うわけですね。あるあるー。
その仕組み、っていうより実現するために埋め込む情報のこと、セキュリティスタンプって言うらしいです。勉強になりました。

IUserSecurityStampStore の使い方

ではセキュリティスタンプを使っていきましょう。

といっても実は、Visual Studio 2013 Update3 で ASP.NET MVC Web アプリケーションを作った場合既定で有効になっています。

設定箇所は App_Start\Startup.Auth.cs の以下のコードです。

public void ConfigureAuth(IAppBuilder app)
{
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        }
    });

    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}

上記コード中で、CookieAuthenticationProvider クラスの OnValidateIdentity プロパティに設定している SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser> メソッドがそうです。なので、もしセキュリティスタンプ機能が必要ない場合はここをコメントアウトすれば OK です。

動かしてみる

では実際に試して見ましょう。

初期設定では、セキュリティスタンプが変更されても、それを検証するまでに 30 分のタイムラグがあります。
なので、検証のために上記 SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser> メソッドvalidateInterval 引数を変更します。

// OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
//  validateInterval: TimeSpan.FromMinutes(30),
//  regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
    validateInterval: TimeSpan.FromSecond(1),
    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))

これで即座に検証されるようになりました。

では、ソリューションをデバッグ実行して、Chrome でアクセスします。
↓の画像は、適当なユーザを作成してログインまで終わったところです。

f:id:kendik:20140817211739j:plain

次は IE で同じ事をやりましょう。

f:id:kendik:20140817211746j:plain

さて。ここで Chrome 側のセッションでパスワードを変更します。

f:id:kendik:20140817211754j:plain

そして、IE 側をリロードすると、、、

f:id:kendik:20140817211808j:plain

ログアウトされました!

ちなみに、パスワード変更じゃなくてログアウトしたらどうなるのっと試して見たら 普通にセッションが継続されました。だめじゃん!!

もしログアウトなど任意のタイミングでセキュリティスタンプを更新したいときは、 UserManager.UpdateSecurityStampAsync メソッドを呼びましょう。

まとめ

まとめると、IUserSecurityStampStore<TUser> インタフェースとはつまり、、、

  • セキュリティスタンプの生成が責務
  • この仕組みにより、任意のタイミングで自身以外のセッションを全て無効化できる
  • が、セキュリティスタンプの検証は別のクラスが行う
  • 細かい設定は OWIN の Configuration で

ということでした。よく出来てますね。