CakePHP4、5の認証処理で認証が通らない際の確認方法と確認箇所の紹介
2025/01/31
CakePHP4、5の認証処理で認証が通らない際の確認方法と確認箇所の紹介
CakePHP4、5の認証処理で「Invalid email or password」が解消しない!
CakePHP4、CakePHP5などではシンプルな認証として、標準的な認証処理がプラグインとして提供されています。
その認証処理を使用している処理が
「何度 ID、PASSを入力しても『Invalid email or password』というメッセージが出て認証が通らない!」
という場合の確認ポイントを紹介します。
「Invalid email or password」が解消しない不具合の発生の経緯
「Aシステム」という既存の稼働中のシステムがありました。
それに対して、関連システムとして「Bシステム」の開発が始まりました。
「Bシステム」の一部の機能は「Aシステム」の APIを経由して情報を取得する処理がありましたので、「Bシステム」の開発と並行して、「Aシステム」の改修も行っていました。
また、いずれも CakePHPと同じ認証処理を使用して作られていましたが、「Aシステム」は「ID+PASS」でログイン認証を行い、「Bシステム」は「E-Mail+PASS」でログイン認証する仕組みでした。
それらのシステムは、私の PCの画面上で同時並行して開発を行っていました。
そして、悲劇が起こるのです。
「Bシステム」のログイン処理を作っているつもりが
「Aシステム」のログイン処理を修正してしまっていた!
のです。
というワケで、
/src/Application.php
に追加する下記の処理の「id」の部分を、知らず知らずのうちに「email」に書き換えてしまっていたのですが、それを調査して不具合点を発見する手続きを紹介します。
まぁ、こんなところではまる方はほとんどいないと思いますが、ほとんどいないため、どうやって確認するかがの記事がなく、途方に暮れてしまいましたので、一人の方でも参考になる方があれば、と思って記事を書きました。
ログイン認証の usernameを指定する Application.phpについて
まず初めに、今回の不具合の原因となった個所は、
/src/Application.php
の下記の 12行目、22行目の「'username' => 'id',」の箇所です。
ここは、認証対象となる「username」と「password」になる項目を指定する項目です。
「username」に「id」を指定すると「ID+PASS」、「email」を指定すると「E-Mail+PASS」で認証するように、ログイン認証する「username」を指定する事ができます。
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
// 識別子をロードして、電子メールとパスワードのフィールドを確認します
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'id',
'password' => 'password',
]
]);
// 認証子をロードするには、最初にセッションを実行する必要があります
$authenticationService->loadAuthenticator('Authentication.Session');
// メールとパスワードを選択するためのフォームデータチェックの設定
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'id',
'password' => 'password',
],
'loginUrl' => '/users/login',
]);
return $authenticationService;
}
上記のソースコードは、下記の Cookbookに記載があるソースとほぼ同じですが、まさに「username」を指定する箇所を、「email」から「id」に変更しています。
https://book.cakephp.org/5/ja/tutorials-and-examples/blog-auth-example/auth.html#id5
ログイン認証の usernameを指定するログイン画面の login.phpについて
また、「username」の項目を変更する際に変更する箇所は下記のログイン画面の項目となります。
/templates/Users/login.php
対象となるファイルは上記のファイルで、変更箇所は 7行目の「= $this->Form->control('id', ['required' => true]) ?>」となります。
<div class="users form">
<?= $this->Flash->render() ?>
<h3>Login</h3>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('ユーザー名とパスワードを入力してください') ?></legend>
<?= $this->Form->control('id', ['required' => true]) ?>
<?= $this->Form->control('password', ['required' => true]) ?>
</fieldset>
<?= $this->Form->submit(__('Login')); ?>
<?= $this->Form->end() ?>
<?= $this->Html->link("Add User", ['action' => 'add']) ?>
</div>
Cookbookでは「email」となっている記述を「id」に変更しています。
CakePHP4、5の認証処理を実装するにあたって、変更する箇所があるとすればこれらの箇所くらいかと思います。
(場合によっては、認証対象のテーブルを「Users」ではないテーブルを対象にする場合は、「Users」の箇所を変更することもあるかもしれませんね。)
ログイン認証で「Invalid email or password」が解消しない場合はログ出力をする
認証処理は実装したけどログインできない、もしくは、私のように先日までは認証処理が動いていたので、何かのメンテナンスをしたことをきっかけに認証が通らなくなった、という場合は、下記の通りログ出力をしてみてください。
/src/Controller/UsersController.php
対象ファイルは上記で、6行目のようにログ出力を追記します。
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
$this->log(var_export($result,true), "error", ['scope' => ['queriesLog']]);
// $this->log(var_export($result,true), "error");
// POSTやGETに関係なく、ユーザーがログインしていればリダイレクトします
if ($result->isValid()) {
// ログイン成功後に /article にリダイレクトします
$redirect = $this->request->getQuery('redirect', [
'controller' => 'Users',
'action' => 'menu',
]);
return $this->redirect($redirect);
}
// ユーザーの送信と認証に失敗した場合にエラーを表示します
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('Invalid email or password'));
}
}
上記の 6行目は「ログスコープ」という機能を利用して、ログファイル「/log/queries.log」に出力するように指定しています。
コメントアウトしていますが、7行目の記述を有効にすると、ログは「/log/error.log」に出力されます。
詳しくは下記の記事を参考にしてください。
「CakePHP4でロギングスコープやログレベルを使用してログを出し分ける方法を解説」
また、CakePHP4系、5系では配列をログ出力をする際は「var_export()」が必要になりました。あわせて上記の記事を参考にしてください。
また、「var_export()」が何者か、については下記の記事を参考にしてください。
「PHPのデバッグで使う print_r、var_dump、var_exportの動作の違い」
ログ出力をすると下記の様なログが出力されます。
2025-01-01 00:00:00 error: Authentication\Authenticator\Result::__set_state(array(
'_status' => 'FAILURE_IDENTITY_NOT_FOUND',
'_data' => NULL,
'_errors' =>
array (
'Password' =>
array (
),
),
))
2行目の「_status」に、認証が認められなかった原因が出力されていますので、これを参考にします。
上記の例では「FAILURE_IDENTITY_NOT_FOUND」となっていますので、単純に、ID、PASSが合っていないのかと思います。
ResultInterface::SUCCESS:成功した場合
ResultInterface::FAILURE_IDENTITY_NOT_FOUND:IDが見つからなかった場合
ResultInterface::FAILURE_CREDENTIALS_INVALID:資格情報が無効な場合
ResultInterface::FAILURE_CREDENTIALS_MISSING:リクエストに認証情報がない場合
ResultInterface::FAILURE_OTHER:その他の種類の失敗
認証のステータスについては下記の記事が参考になります。(CakePHP3系以降の Cookbookには記載がないようです。)
CakePHP2 Cookbook 認証コンポーネント
https://www.m-kobayashi.org/CakePHP/Documents/Plugin/Authentication/authentication-component.html#
また、この記事を書くきっかけになった「Application.php」の「username」が間違っている場合は、「FAILURE_CREDENTIALS_MISSING」となりました。
ログイン画面で入力している「username(ID)」と認証に使用する「username(email)」が違うため、「POSTした値に認証情報が含まれていないよ」というエラーになった、ということです。
このように、ログインのステータスをログ出力することで、なぜエラーになっているのか、少しは情報が増えるかと思います。
ちなみに、今回さらに混乱をした原因として、入力しているパスワード「test」はコピペした値を入力していました。
が、「test」は「test」だけではなく「(タブ)test」という状態のものをコピーしていて、正しい「test」だけではなかったため、先の「FAILURE_CREDENTIALS_MISSING」の不具合が解消しても、「FAILURE_IDENTITY_NOT_FOUND」のエラーが解消しないという、二重の不具合でより解消に時間がかかるというものでした。
「FAILURE_IDENTITY_NOT_FOUND」のエラーが出るときは、入力値を確認するために、下記の 6行目のように、入力情報である「$this->request」の方もログ出力をしてみるといいでしょう。
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
$this->log(var_export($this->request), "error", ['scope' => ['queriesLog']]);
$this->log(var_export($result,true), "error", ['scope' => ['queriesLog']]);
:
:
略
この時、ログ出力に「var_export()」を使用することで、「test」の前に何か入っている、と気づくきっかけになるのではないかと思います。
(この点は「print_r()」より優れている点かと思います。)
というワケで、CakePHPの認証処理もエラーが発生して想定の動作をしない場合は、ログ出力をして、エラーメッセージを読むことで少しずつ原因に近づいていく対処が必要ということになりますね。
非常にレアな状況に対応するための記事かと思いますが、どなたかのお役に立てば、と思います。
ログイン認証を必要としない Action(ページ)を指定する方法
また、ユーザ認証処理によって、ログイン認証できないため、ユーザ情報の登録も更新もできなくて困っている、という場合は、下記の
/src/Controller/UsersController.php
の最初の方に記述しているであろう下記の認証が通っていなくてもアクセスできる Actionを指定する箇所に追記します。
認証処理を設置する Cookbookの記事にも記載がありますが、忘れている場合もあるかと思いますので、改めて記載しておきます。
具体的には、6行目の「['login']」となっている箇所を「['login',"add","edit"]」のように、Action名を追加します。
追加された Actionは認証がなくてもアクセスができますので、新しいユーザの登録や、ユーザ情報を更新して、間違いないパスワードを生成するといいでしょう。
public function beforeFilter(\Cake\Event\EventInterface $event)
{
parent::beforeFilter($event);
// ログインアクションを認証を必要としないように設定することで、
// 無限リダイレクトループの問題を防ぐことができます
$this->Authentication->addUnauthenticatedActions(['login']);
}
CakePHP4系、5系の認証に関する参考記事
最後に、CakePHP4系、5系で提供されている認証処理についての公式 Cookbookの記事の紹介です。
CakePHP5 Cookbook シンプルな認証と認可のアプリケーション
https://book.cakephp.org/5/ja/tutorials-and-examples/blog-auth-example/auth.html
CakePHP5 Cookbook CMS チュートリアル – 認証
https://book.cakephp.org/5/ja/tutorials-and-examples/cms/authentication.html
CakePHP4 Cookbook シンプルな認証と認可のアプリケーション
https://book.cakephp.org/4/ja/tutorials-and-examples/blog-auth-example/auth.html
CakePHP4 Cookbook CMS チュートリアル – 認証
https://book.cakephp.org/4/ja/tutorials-and-examples/cms/authentication.html
上記は、CakePHP4と 5の認証処理の紹介ですが、読んでもらえば分かる通り、4系と 5系の認証処理はほとんど同じです。
「CakePHP5系で認証機能のAuthenticationプラグインをインストール・エラー発生注意」
ですが、上記で記事にしていますが、使用するプラグイン「cakephp/authentication」は、4系では Ver.2、5系では Ver.3となっていますので、その点の注意は必要です。(公式 Cookbookが間違えていますので注意が必要です。)
その他の関連記事としては下記の記事でしょうか。
CakePHP4 Cookbook AuthComponent
https://book.cakephp.org/4/ja/controllers/components/authentication.html
CakePHP3系の認証処理も似たような認証処理として提供されていますが、CakePHP4になる時に少し変わりましたよ、という案内です。
これから CakePHP3系で新しいシステムの開発をすることは少ないかと思いますが、CakePHP3系から 5系へのシステム移行の際などには違いがあることを認識しておく方がよさそうです。
CakePHPの上記の認証処理はシンプルな造りで、追加する項目も、各システムに合わせて変更する箇所も少ないため、ほとんどの場合は迷うことなく実装することができるでしょう。
ですが、シンプルな造りであるからこそ、上手くいかなかったときは悩みが深まるのではないかとも思います。
CakePHP5の関連記事
CakePHPのpostlinkで生成した削除リンクをクリックしても処理が実行されない対処法CakePHP4、5のユーザ認証でID、PASS以外の削除フラグなども条件加える方法
CakePHP4、CakePHP5系の認証処理でログインの有無の確認、ユーザ情報の取得の方法
CakePHP4、5で$_SERVERと同じようにURIを取得する「getUri()」の紹介
getParam('action')で取得するアクション名は別関数に移動しても不変CakePHP4系、CakePHP5系のexists()でカラムを指定して値の有無をチェックする方法解説
CakePHP4、5のnewEmptyEntityで作成したオブジェクトは空なのか、確認してみた
CakePHP4、5でSELECT telephone as tel FROM usersの様にasでカラムに別名を付ける方法
CakePHP4、5の認証処理で認証が通らない際の確認方法と確認箇所の紹介
CakePHP5系で認証機能のAuthenticationプラグインをインストール・エラー発生注意
その他の「CakePHP5」に関する記事一覧
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
CakePHP3でアソシエーション先のカラムでデータをソートして取得したい
アソシエーション先のテーブルのカラムをキーにソートをしたデータを取得したい!ときの記述方法を解説。「orderAsc()」ではなく「contain()」の中にSort条件を記述する。
-
-
CakePHP 2.3で確認画面付きのお問い合わせフォームの作り方
CakePHPで確認画面付きのお問い合わせフォーム、メールフォームの作り方をサンプルを提示しながら解説。
-
-
CakePHP3のfriendsofcake/searchでブックマークチュートリアルのタグ検索を実装
CakePHP3のCookbookにあるブックマークチュートリアル。ここで紹介されているタグで検索する処理を検索プラグイン「friendsofcake/search」で実現する方法を解説しました。
-
-
CakePHP3にデザインテンプレートBootstrapを導入する方法・friendsofcake/bootstrap-ui使用
CakePHP3にプラグイン「friendsofcake/bootstrap-ui」、デザインテンプレート「Bootstrap」を設置する手順を解説。Bootstrapの簡単な使い方やデフォルトのデザインとの混在方法なども解説。
-
-
MySQL+CakePHPのdate型、datetime型項目は「2999-12-31」までしか扱えない
CakePHPの日付、日時の型であるdate型、datetime型の最大値は2999-12-31となっている。MySQLは9999年までなので違いがあるので注意が必要だ。
-
-
getParam('action')で取得するアクション名は別関数に移動しても不変CakePHP4系、5系では「getParam()」で処理中のアクション名を取得できる。そのアクションから別関数を呼び出してた関数でアクション名を調べたが同一の名称だった。
-
-
CakePHP3のHtmlHelperのLink設定のまとめ。mailto、URL、Root/Homeのリンクなども
CakePHP3でHtmlHelperを使ってリンクの設定をする方法のまとめ。基本形からURLを指定、class、id、targetを指定、mailtoのリンク、画像をアンカーに、JavaScriptのダイアログなどの解説。
-
-
CakePHPで Auto Incrementを外すと Duplicate entry ‘0’ for keyのエラーが出るかも
CakePHPでAuto Incrementの設定を変更したときに「Duplicate entry ‘0’ for key」のエラーが出た。原因はModel内で IDを編集する処理の追加を忘れていたからだった。
-
-
CakePHP3の更新画面でUpload Plugin 3.0を使う方法、viewで使う方法解説・その3
CakePHP3でファイル、画像をアップロードするプラグイン、upload plugin 3を導入する手順を解説した記事。3部作のその3で記事を更新する際のファイルの取り回しなどについてを解説。
-
-
CakePHP3のUpload Plugin 3.0をバリデーションなど実運用向けのカスタマイズ方法解説・その2
CakePHP3でファイル、画像をアップロードするプラグイン、upload plugin 3を導入する手順を解説した記事。3部作のその2でバリデーションなどの実用的なカスタマイズ方法を解説。