LoginSignup
41
22

More than 3 years have passed since last update.

Django でログインセッションの有効期限を設定するのが意外と大変だった

Last updated at Posted at 2020-09-02

概要

  • Django 3.0 には最初からユーザーのログイン認証とセッション管理の機能があります
  • しかしデフォルト設定のままでは今回のセキュリティ要件を満たせなかったので、設定を変更する必要がありました
  • ブラウザを閉じたらセッションを終了する要件については、条件付きでの実現となりました

それぞれの要件と対応

1. 任意の有効期間を設定したい

  • デフォルト: 2 週間
  • 希望要件: 15分間 〜 2時間の任意の期間に設定したい

設定方法

settings.py で定義します。
初期状態の settings.py では定義が省略されているので、例えば 1 時間に設定したい場合は以下の行を追記します。

settings.py
SESSION_COOKIE_AGE = 3600

参考:
SESSION_COOKIE_AGE

確認方法

データベースに接続して、新しいログインによって django_session テーブルに挿入された行の expire_date 列の値が、ログイン時の UTC 時刻 + 設定した秒数になっていることで確認できます。

2. スマホのスリープのように、最後に操作してから放置した時間で期限切れにしたい

  • デフォルト: ユーザーの操作に関係なく、ログイン時から SESSION_COOKIE_AGE 秒後に期限が切れる
  • 希望要件: 最後にいずれかのページをロードしてから SESSION_COOKIE_AGE 秒後に期限切れとしたい

設定方法

これも初期状態の settings.py では定義が省略されているので、以下の行を追記します。

settings.py
SESSION_SAVE_EVERY_REQUEST = True

参考:
セッションが保存されるタイミング
SESSION_SAVE_EVERY_REQUEST

確認方法

データベースに接続して、画面をリロードするたびに django_session テーブルの expire_date 列の値が更新されることで確認できます。
デフォルトではログイン認証時に expire_date 列の値が決まり、その後の操作で expire_date 列の値は更新されません。

3. セッションをデータベースで管理したい

  • デフォルト: セッションをデータベースで管理する

これはデフォルトのままで希望どおりです。
サーバーのローカルメモリで管理する場合に比べてパフォーマンス面では不利ですが、ロードバランサーなどで前回と違うサーバーにリクエストが届いた場合でも正しく処理されます。

設定方法

初期状態の settings.py から変更する必要はありません。以下のとおりになっていればデータベースでセッションが管理されます。

  • INSTALLED_APPS"django.contrib.sessions" が含まれていること
  • MIDDLEWARE"django.contrib.sessions.middleware.SessionMiddleware" が含まれていること
  • SESSION_ENGINE が定義されていないか、または設定値が django.contrib.sessions.backends.db であること

参考: セッションエンジンを設定する

確認方法

データベースに接続して、ログインのたびに django_session テーブルに新しい行が挿入されることで確認できます。

課題

django_session テーブルに保存されたセッションの行は、明示的なログアウト処理(内部で django.contrib.auth.logout() の呼び出し)では削除されるのですが、有効期限が切れただけでは自動的に削除されません。

このため行が増え続けることを防ぐためには、以下のコマンドを時々実行して期限切れのセッションを削除する必要があります。

python manage.py clearsessions

4. Web ブラウザを閉じたらセッションを終了したい

  • デフォルト: ブラウザを閉じても SESSION_COOKIE_AGE で設定された期限までセッションが維持される
  • 希望要件: 設定された期限に関係なく、ブラウザを閉じたらセッションを終了したい

設定方法

これも初期状態の settings.py では省略されているので、以下の行を追記します。

settings.py
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

参考:
ブラウザ起動中のみ有効なセッション vs. 永続的なセッション
SESSION_EXPIRE_AT_BROWSER_CLOSE

確認方法

ブラウザを閉じてから起動して、同じページを開こうとするとログインを求められます。
デフォルトでは再ログインすることなく同じページが開きます。

課題

この動作はブラウザ自身が終了時に cookie を破棄するかどうかに依存しているため、以下のブラウザと設定では、ブラウザを閉じてもセッションが終了しませんでした。

  • Google Chrome 85: 「設定」>「起動時」>「前回開いていたページを開く」が選択されている場合
  • Firefox 80: 「設定」>「一般」>「起動」>「前回のセッションを復元する」が有効な場合

参考

41
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
22