none
Session切れした際にログアウトさせる方法 RRS feed

  • 質問

  • お世話になります。
    ASP.NET MVCにて、会員用サイトを作成しています。

    Visual StudioでMVCサイトを作ると標準で備わっているASP.NET Identityにてログイン処理をしています。

    ログインした際に、会員の名称や会員固有の設定情報を呼び出し、Sessionに保存しています。
    その後、各ControllerやView内にてSessionの値を呼び出しています。

    Sessionの有効期間は長めに設定しているため、現状では問題は起きていないものの、何らかの理由でSession切れが発生した場合、
    「ログインは出来ているのにSessionは無い」 状態になり、操作に不具合が生じる事が予想されます。

    できればSessionが切れた際に強制的にログアウト処理をしたいところですが、
    <sessionState mode="StateServer" ~ />
    になっているため、Global.asaxのSession_OnEndイベントは効きません。InProcでは当方の環境では不都合が多いため、できれば使いたくありません。

    そこで、アクションフィルターを作成し、OnActionExecuting() 内にてSessionが切れたか判定し、切れていれば強制ログアウトするよう、以下のようなコードを書き加えました。

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        bool sessionIsValid = true;
        
        if (HttpContext.Current.Session == null)
        {
          sessionIsValid = false;
        }
        else if (HttpContext.Current.Session.Keys.Count <= 0)
        {
          sessionIsValid = false;
        }
        
        if (!sessionIsValid)
        {
          filterContext.Result = new RedirectResult("/account/forcedlogoff");
          return;
        }
    }
    今のところ正常に動いていますが、常道が今ひとつわからない中、もっと良い方法があれば教えて頂ければ幸いです。

    2017年8月25日 7:36

回答

  • 【追伸】

    上のレスで、"質問者さんが行ったようにアクションフィルターで Session データが有効か否かを調べて処置する以外は自分も思いつきません" と書きましたが、もう一つ別の方法を思いついたので追記します。

    > ログインした際に、会員の名称や会員固有の設定情報を呼び出し、Sessionに保存しています。

    「会員の名称や会員固有の設定情報」というのが何だか分かりませんが、可能であればプロファイル情報に含めてそれから取得するようにしてはいかがですか?

    アクセスするたび DB にクエリを投げて取得するのが嫌だということがあれば、プロファイル情報を ClaimsIdentity へ追加して認証クッキーから取得するという方法もあります。その方法の詳細は以下の記事を見てください。

    プロファイル情報を ClaimsIdentity へ追加
    http://surferonwww.info/BlogEngine/post/2017/04/16/add-user-profile-information-to-claimsidentity.aspx

    上の記事は Web Froms アプリを対象にしてますが、MVC でも同様に可能です。

    2017年8月25日 8:39

すべての返信

  • > 今のところ正常に動いていますが、常道が今ひとつわからない中、もっと良い方法があれば教えて頂ければ幸いです。

    「もっと良い」かどうかは質問者さんの都合等もあるでしょうから分かりませんが・・・

    ReportViewer は再生するのが簡単ではないデータを保存するのに Session を使っています。そして、デフォルトではセッションがタイムアウトしないように自動的に ping をかけるようにしているそうです。

    詳しくは以下の記事を見てください。

    ReportViewer と Session
    http://surferonwww.info/BlogEngine/post/2015/09/07/reportviewer-and-session-state.aspx

    そういう方法も検討されてはいかがでしょう?

    ReportViwer がどのように自動的に ping をかけているかは不明ですが、MVC アプリでも Timer 等を使って定期的に要求をかけることは可能だと思います。

    その方法が NG ということであれば、質問者さんが行ったようにアクションフィルターで Session データが有効か否かを調べて処置する以外は自分も思いつきません。

    2017年8月25日 8:27
  • 【追伸】

    上のレスで、"質問者さんが行ったようにアクションフィルターで Session データが有効か否かを調べて処置する以外は自分も思いつきません" と書きましたが、もう一つ別の方法を思いついたので追記します。

    > ログインした際に、会員の名称や会員固有の設定情報を呼び出し、Sessionに保存しています。

    「会員の名称や会員固有の設定情報」というのが何だか分かりませんが、可能であればプロファイル情報に含めてそれから取得するようにしてはいかがですか?

    アクセスするたび DB にクエリを投げて取得するのが嫌だということがあれば、プロファイル情報を ClaimsIdentity へ追加して認証クッキーから取得するという方法もあります。その方法の詳細は以下の記事を見てください。

    プロファイル情報を ClaimsIdentity へ追加
    http://surferonwww.info/BlogEngine/post/2017/04/16/add-user-profile-information-to-claimsidentity.aspx

    上の記事は Web Froms アプリを対象にしてますが、MVC でも同様に可能です。

    2017年8月25日 8:39
  • SurferOnWww様

    諸々のご提案ありがとうございます。
    ReportViewerは使ったことがなかったためハードルが高そうに感じられましたが、ClaimIdentityは今回の要望に合っていそうに思えます。

    参照ページを読ませて頂いた限り、プロファイル情報が認証クッキーに含まれるため、Sessionと違いプロファイル情報の読み出しが先に出来なくなる事がなさそうです。

    ただ、参照ページでも触れられている「ページを描画するたびにデータベースにクエリを発行してプロファイル情報を取得するのは負荷が重そう」と同じ理由で私もSessionを使ったり今回のClaimIdentityを検討していますが、同じく記載されている「実は気にするほどの差はないのかもしれません」という可能性も頭をよぎっていますw

    いずれにしても、色々とお知恵をいただき、感謝いたします。

    2017年8月28日 0:54
  • > ReportViewerは使ったことがなかったためハードルが高そうに感じられましたが、

    上の私の提案は、ReportViewer を使うとかその機能を流用するとかいうわけではなく、「(ReportViewer がやっているように)定期的に要求をかけて Session タイムアウト時間を延ばす」ということです。

    例えば、JavaScript の setInterval と jQuery ajax を組み合わせて定期的に要求を出すことができます。

    興味があれば試してみてはいかがですか?


    > 「実は気にするほどの差はないのかもしれません」という可能性も頭をよぎっていますw

    Session タイムアウト(デフォルトで 20 分)が気になるということは、DB にクエリを投げてプロファイル情報を取得する頻度は高くない(低い?)ということのように思えます。

    そうであれば Session とか ClaimsIdentity を使わなくても、直接 DB から取得しても問題なさそうですが。

    2017年8月28日 1:13
  • > (ReportViewer がやっているように)定期的に要求をかけてSession タイムアウト時間を延ばす」ということです。

    > 例えば、JavaScript の setInterval と jQuery ajax を組み合わせて定期的に要求を出すことができます。

    そういう事だったんですね!
    ただ、確かにこの方法だとSessionを維持し続ける事は可能ですが、
    ユーザーがブラウザを開きっぱなしの状態でWindowsを休止状態やスリープにして暫く後にアクセスすると、やはり認証クッキーだけが残りSessionはタイムアウトされてしまうと思います。

    当初のアクションフィルターによるSessionチェックで不都合が出てきたら、DBに毎回参照しにいく方式も考えてみます。

    度々のご助言ありがとうございました。

    2017年8月28日 4:16