ことの発端(ほったん)
色々な仕事があるわけで… (^^;
通常の管理画面とか必ず認証が必要なサイトであれば、
- 最初にログイン画面を出す。
- ログイン処理を行う。
- トップページに遷移する。
でいいですが、こんな仕様もあったりします。
- ゲスト(未ログイン)でもサイトを参照できる
- 各ページの右上とかにログインボタンがある。
- 好きな時にログインボタンからログインできるが、ログイン後はボタンを押したページに戻りたい。
- 認証が必要なページに行った場合は自動的にログイン画面になり、ログイン後は目的のページに遷移したい。
- ログインすると、各画面でユーザ情報が参照できる。
とりあえず、1 と 5 は作りの問題。4 は laravel の機能でできますが、
3 は、標準機能で、そのまま実装すると / に戻ってしまいます。
いろいろ解説
LoginController 解析
make:auth で作られる app\Http\Controller\Auth\LoginController.php はほぼ空っぽで
中味は、フレームワークの Illuminate\Foundation\Auth\AuthenticatesUsers で実装されています。
AuthenticatesUsers を見てみると
ログインできた後は redirect()->intended($this->redirectPath()); を呼んでいます。
これは、認証フィルターでキャッチされる前にアクセスしたURLへリダイレクトさせる処理です。
このため、上の「こんな仕様」の4番は、ログイン後に目的のページにリダイレクトできるのです。
intended 解析
intended は「意図された」という意味ですが、機能は以下です。
- セッションの 'url.intended' に値が設定されていたらそこにリダイレクトする。
- 値が設定されていなかったら '/' にリダイレクトする。
今回の問題と対策
認証フィルターはキャッチ前に 'url.intended' に参照元URLを設定しているわけですが、
ログイン画面が直接呼ばれた場合は、その値が設定されないため '/' 画面に固定で遷移してしまうわけです。
であれば、ログイン画面に遷移した際に 'url.intended' を設定してやれば認証フィルターでキャッチされたと同様の流れになるはずです。
実装
ログインフォームを表示する showLoginForm メソッドを LoginController.php にオーバーライドします。
直前画面を 'url.intended' セッションに設定します。
これで認証フィルターと同じ流れになるはずです。
/**
* Show the application's login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
// ここから
if (array_key_exists('HTTP_REFERER', $_SERVER)) {
$path = parse_url($_SERVER['HTTP_REFERER']); // URLを分解
if (array_key_exists('host', $path)) {
if ($path['host'] == $_SERVER['HTTP_HOST']) { // ホスト部分が自ホストと同じ
session(['url.intended' => $_SERVER['HTTP_REFERER']]);
}
}
}
// ここまで追加
return view('auth.login');
}
これで、どの画面でログインボタンを押しても、元の画面に戻れるようになりました。