先ほどの記事で、サブディレクトリに配置した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。地道に頑張りたいとおもいます。