LoginSignup
8
10

More than 5 years have passed since last update.

CAKEPHP3 : ログイン後のリダイレクト先の制御

Last updated at Posted at 2016-04-27

記事の対象

  1. AuthComponent によりアクセス制御を行っている
  2. ログインしたら想定してない場所にリダイレクトした
  3. (特に) リンクでの移動以外でアクセス(ajaxなど)するアクションに,ログインしていないとアクセスが許可されないものがある

本文

AuthComponent::redirectUrl() について

AuthComponentには redirectUrl() というメソッドがあり,これは次の優先順位でいずれかのURLを返す.

  1. 認証情報ストレージ(デフォルトでは \App\Auth\Storage\SessionStorage で,セッションに記録される)の redirectUrl() メソッドで取得できるURL
    • AuthComponentによりアクセスを禁止された場合,自動でそのURLがセットされる
    • AuthComponent::redirectUrl($url) にてセット可能
  2. AuthComponentの設定で 'loginRedirect' により設定された URL
  3. ホーム

これは次のような遷移を行うのに大変便利である.

  1. ログインが必要なアクションに,ログインしていないユーザがアクセスした場合に,ログインページへリダイレクトする
  2. ログインする
  3. 先ほどアクセスしようとしたページヘリダイレクトする

公式のチュートリアルでも次のように使われている.

ブックマークチュートリアル2より転載
// In src/Controller/UsersController.php
public function login()
{
    if ($this->request->is('post')) {
        $user = $this->Auth->identify();
        if ($user) {
            $this->Auth->setUser($user);
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Flash->error('Your username or password is incorrect.');
    }
}

問題

便利であるが,redirectUrl()が最優先で返す「アクセスを禁止されたURL」は何もしなければログインするまで(あるいはストレージの記録が消えるまで)残ったままになっている.
そのため,アクセス禁止後にすぐにログインせずに,別のページを経由して,あらためてログインページからログインした際にも,最後にアクセス禁止されたURLを返す.
この結果,チュートリアルの例では,ユーザや開発者が想定していなかったURLにリダイレクトしてしまうという問題が発生しうる.

対策としてこのようにした

AuthComponent::redirectUrl() は コールすると,セットされている値を失う.
それを利用して次のようにした.

どのアクションからも経由され,各アクションメソッドを実行したあとに実行される箇所,例えばAppController::beforRender() あたりに,次のようにする.

class AppController extends Controller
{
    public function beforeRender()
    {
        empty($this->protectAuthRedirect) && $this->Auth->redirectUrl();
    }
}

そしてログインアクションなどの,アクセスするときにredirectUrlをクリアしたくないアクションでは,コントローラの $protectAuthRedirectプロパティにtrueをセットすれば良い.

さらに面倒な・・・

ajaxで利用するログインしたユーザだけがアクセスできるアクションを用意している場合,問題がもう少し面倒になる.

セッション期限切れなどでajaxのアクセスに403Forbiddenが返ってくるようになり,ユーザがログインページへ直行した場合,この設定だけだと,ログイン直後に ajaxでアクセスしたURLへリダイレクトことになってしまう.

これはもうloginRedirect()の取得値をフィルターに通すしかない気がする.
(だれかもっとスマートなやり方あれば教えて下さい.)

8
10
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
8
10