【CakePHP4】Authentication plugin:何度やってもログインできなかった原因は ‘loginUrl’ => も Router::url で指定してなかったからだった(>_<)【Router使おう】

先ほどの記事で、サブディレクトリに配置したCake4アプリでAuthenticationを動かそうとするとリダイレクト先が荒ぶる…のを解消できたと浮かれておりました。優雅に紅茶を淹れたりなんかして、余裕ぶっこいていました。

数分後、いざログイン画面へ…今度は正しいID/Passwordを入れてるはずなのに、何度やってもログイン出来ないという発狂状態に陥りました。

チュートリアル通りに進めてたのですが…

https://book.cakephp.org/4/en/tutorials-and-examples/cms/authentication.html

PasswordHasherが間違ってるのかとか、ちゃんとハッシュ化されてないのか?とか、saltの再設定とか、何度やっても、冷酷に

Invalid username or password

と表示され、一向にログインが出来ません。チュートリアル通り、というかほぼコピペなのに(>_<)

//UsersController.php
    public function login()
    {
        $result = $this->Authentication->getResult();
        // If the user is logged in send them away.
        if ($result->isValid()) {
            $target = $this->Authentication->getLoginRedirect() ?? '/home';
            return $this->redirect($target);
        }
        if ($this->request->is('post') && !$result->isValid()) {
            $this->Flash->error('Invalid username or password');
        }
    }

もう3時間が経過し、オッサンにはCake4はもう無理なんだ、おとなしくCake2に戻ろうか…と諦めかけていたのですが

$resultをdebugしたら原因が分かった…

チュートリアル通りに進めるログイン機構は、認証出来たか否かをすべてプラグイン任せで $result で受け取っています。isValid() ぐらいしか返ってきてないと思い込んでいたのですが、ダメ元で debug 仕掛けてみたところ、、、

$result = $this->Authentication->getResult();
debug($result);
//debug の結果($resultの中身)
object(Authentication\Authenticator\Result) {
	[protected] _status => 'FAILURE_OTHER'
	[protected] _data => null
	[protected] _errors => [
		(int) 0 => 'Login URL `https://testserver/*****/users/login` did not match `/users/login`.'
	]
}

なんと、$result->_errorsの中に詳しく教えてくれていた(^_^;

[protected] _errors => [
(int) 0 => ‘Login URL https://testserver/*****/users/login did not match /users/login.’

!!なんか出てる!!

$authenticationService->loadAuthenticator(‘Authentication.Form’, の、
‘loginUrl’ => ●●●
を指定していた場合、そこからのPOST送信以外は認証すらされず、門前払いされるようです。
で、ここが、先ほどの記事のunauthenticatedRedirectと同様、’/users/login’ と書いても、サブディレクトリに設置していることを判別出来ずに、サイトルートからのアドレスとなってしまうため、

Login URL https://testserver/*****/users/login did not match /users/login.’

指定された送信元と違うURLからログイン試行されてるよ!みたいな感じで門前払いしてくれているようです。

有能な番犬なのか、融通利かずの堅物なのか…。

結論: サブディレクトリに配置して、 $authenticationService->loadAuthenticator(‘Authentication.Form’ の ‘loginUrl’ を指定する場合も、 Router::url() を使いましょう

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    $authenticationService = new AuthenticationService([
        'unauthenticatedRedirect' =>   Router::url('/users/login'), //←こっちをRouterにしましたので
        'queryParam' => 'redirect',
    ]);

    // Load identifiers, ensure we check email and password fields
    $authenticationService->loadIdentifier('Authentication.Password', [
        'fields' => [
            'username' => 'username',
            'password' => 'password',
        ]
    ]);

    // Load the authenticators, you want session first
    $authenticationService->loadAuthenticator('Authentication.Session');
    // Configure form data check to pick email and password
    $authenticationService->loadAuthenticator('Authentication.Form', [
        'fields' => [
            'username' => 'username',
            'password' => 'password',
        ],
        'loginUrl' =>   Router::url('/users/login'), //←指定するならこっちもRouter::urlに変更!
    ]);

    return $authenticationService;
}

これで、やっとログインが出来る事が確認できました・・・。長かった…

$result は、パスワード違いやIDがない場合など、いろんなステータスを返してくれています。

//パスワードが違うなどの場合
object(Authentication\Authenticator\Result) {
	[protected] _status => 'FAILURE_IDENTITY_NOT_FOUND'
	[protected] _data => null
	[protected] _errors => [
		'Password' => []
	]
}
//usernameやpasswordが送信されてないなどの場合
object(Authentication\Authenticator\Result) {
	[protected] _status => 'FAILURE_CREDENTIALS_MISSING'
	[protected] _data => null
	[protected] _errors => [
		(int) 0 => 'Login credentials not found'
	]
}

ココロ折れそう…、先が思いやられる…orz。地道に頑張りたいとおもいます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です