前回のCakePHPでの同時ログイン禁止の続き。
過去のセッションをすべてDBから消して強制ログアウトした後の挙動と、
「他でログインしたからこのセッションはログアウトした」という表示を出す方法について。
DBに無いSession idが来た時の挙動
Sessionsテーブルからデータを消して強制ログアウトさせる方法の場合、ブラウザからはDB側データが消された事は分からないので、cookieが残っていれば普通に過去のセッションIDを送ってくる。
この時のサーバーサイドの挙動は以下の通り。
- 何らかのURLにユーザーからアクセスされる
- セッション開始(session_start())され、openハンドラとreadハンドラが一回呼ばれる
- この呼び出しはCakePHPというよりPHP自体の機能
- カスタムSessionHandlerを登録してるので、そこで定義した関数が呼ばれる
- openハンドラは定義してないので継承元のDatabaseSessionへ、そこでも結局何もしない
- readハンドラでDB読みに行き、当然DBに行が無いので、空文字列""を返す
- Session id再発行。これ以降は再発行されたsession idで通常の動作になる
- 内部でid振りなおし
- writeハンドラ呼ばれてDBに書き込み
- ユーザーにも新IDのcookieを返す
- Authは当然失敗、ログインアクションにredirecされる。これの通り。
そしてログイン画面にリダイレクト後、
- 再発行されたsession idのcookieを受け取る
- DBにデータがあるので、ごく普通のセッション
- =この場所では強制ログアウト後か否かは知り得ない
強制ログアウト時に表示を出す
二重ログイン後か否かを判断して強制ログアウトされた旨のメッセージを出したい場合、
上の挙動の通りリダイレクト後のログイン画面では知り様が無い。
よって、最初にアクセスされた、リダイレクト前のページで検知する必要がある。
検知はカスタムSessionHandlerで特定の挙動をしたときにフラグを立てるようにして、
Auth失敗時にこのフラグを確認する。
場所はAppControllerのbeforeFilter()あたり。当然ここに来るまでにセッションID再発行まで終わっている。
以下①有り && ②無し が強制ログアウト時の状況になる。
① read() でカラ文字列を返した
② destroy() が呼ばれた
beforeFilter()内
if (!$this->Auth->user()) {
//ここでフラグチェック
}
補足 ②destroy有無フラグが必要な理由
普通にログアウト・再ログインする際にもセッションID再発行が行われる。
この時もread()で空文字返す処理があるので、①だけで絞り込めない。
この時はdestroyも呼ばれるので、この有無を絞り込みに使う。