モノレビュー

YiiでCookieをOffにするとログイン時にreturnUrlが設定されていない

Cookieなし、URL埋め込み型セッションIDを使っているときに、returnUrlが設定されずに、ログイン後にindex.phpに飛ばされてしまいます。

これでは不便なのでちょっと調べてみることにしました。

通常はreturnUrlはセッションに「セッションID__returnRul」の変数で保存されていますが、cookieオフの設定では$_SESSIONの中身を読み出しても設定されていませんでした。

Webで探しても自分で設定しなさいとか、よくわかんないや、バグじゃね?みたいな情報しか見つけられなかったので、CWebUser.phpを読んでいくことに。

ReturnUrlプロパティが設定されるまで

CAccessControlFilter.php
accessDeniedメソッドからCWebUser.phpのloginRequireメソッドを呼び出し。

CWebUser.php
loginRequired→setReturnUrlメソッド→setStateメソッド。ここでセッションID_returnUrlを設定している。

Cookie関係なくセットはされているようだけど、ログインページに飛ばす際にセッションIDなしでredirectされているのが原因のようです。

原因は

認証が必要なページにアクセスしたときに振られたセッションIDにはreturnUrlが含まれていますが、リダイレクト後はセッションIDが含まれないURL(/site/login)のため、$_SESSIONにも値が入っていないというのが原因でした。

対策方法

CWebUser.phpのloginRequiredメソッドの$this->redirect()部分にセッションIDを含める方法と、requestオブジェクトのredirectを書き換える方法があります。

ほかの部分でもredirect時にセッションIDが含まれていないということがおこるので、問題の根っこ部分$this->redirect自体をオーバーライドすることにします。

まずは/protected/HttpRequest.phpを作成、CHttpRequestを継承してredirect部分だけオーバーライドします。

/protected/components/HttpRequest.php

class HttpRequest extends CHttpRequest {
    public function redirect($url, $terminate=true, $statusCode=302) {
        if (strpos($url, '/') === 0) {
            if (strpos($url, '?') !== false) {
                $url = $this->getHostInfo() . $url;
            } else {
                $url = $this->getHostInfo() . $url . (SID ? ('?' . htmlspecialchars(SID, ENT_QUOTES, Yii::app()->charset)) : '');
            }
        }
        header('Location: ' . $url, true, $statusCode);
        if ($terminate)
            Yii::app()->end();
    }

}

つぎに設定ファイルでrequestオブジェクトにHttpRequestクラスを使うように指定します。

/protected/config/main.php

‘components’ => array(
    ‘request’ => array(
        ‘class’ => ‘HttpRequest’,
        ‘enableCsrfValidation’ => true,
    ),

これでreturnUrlが設定されるようになった。

モバイルバージョンを終了