CakePHP5入門【CakePHP5認証編①】一般的な認証

A子
ログイン認証の機能を作らないとダメじゃん
それって簡単に作れるものなの?

B美

C菜

B美

A子
(公式ページなのは同じだけど…)
C菜の示した日本語のページのほうが良いんだけど…

C菜
バージョンが違いますよ~

B美
最新バージョンである「3.x」って、まだ日本語には翻訳されてないのよね(苦笑)
さらに言えば、CakePHP5の認証サンプルであるこちらのページについても、実は古い認証バージョン(2.x)のほうで書かれているわ
(クリックすると別ウィンドウで開きます)
※2025年3月時点(将来、公式ページが修正される可能性はあります)

A子
(ただし、古いバージョンであることには注意して…)
とりあえずデータベース名は「authdb」にして、usersテーブルの定義はさっきの公式ページの通りに作ってみよう
(単なるコピペだけど…)
create database authdb;
use authdb; CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255), password VARCHAR(255), created DATETIME DEFAULT NULL, modified DATETIME DEFAULT NULL ); |
あ、「role」という項目は削除したよ
んで、これを「authdb.sql」というファイル名で保存してっと…


C菜
そのファイル(authdb.sql)を「mysql」コマンドに渡しますね~
mysql -u root -p < authdb.sql[Enter] |
もちろん「MATE端末」上で実行です~


B美
んじゃ、次は「CakePHP5」のプロジェクトを作成してね

A子
(超・適当(笑))
cd html[Enter]
composer create-project --prefer-dist cakephp/app authapp[Enter] |
もちろん、途中で止まったら「Y」を入力して[Enter]キーだね

↓


C菜

A子
(面倒だし…)
cd authapp[Enter]
bin/cake bake all users[Enter] |
で良いんだよね?

B美
先に「config」ディレクトリの中の「app.php」と「app_local.php」を修正しておきなさいね
でないと、bakeコマンドが通らない(エラーになる)わよ

A子
ん?何行目だったっけ?

C菜

A子
もはや慣れたもんだね
んじゃ、あらためて…
cd authapp[Enter]
bin/cake bake all users[Enter] |

↓


C菜
あ~、ただし…
データベーステーブルから「role」項目を(A子社長が勝手に)削除したので、それに関連するコードについては削りました~
public function validationDefault(Validator $validator): Validator
{ return $validator ->notEmpty('email', 'A email is required') ->email('email') ->notEmpty('password', 'A password is required'); } |

↓


A子
(さっき「src/Controller」ディレクトリの中にbakeコマンドで作ったけど…)
あれ?
特に書き換えるところは無さそうだよ

B美
(ここでは、いったんそのままにしておきましょう)
んじゃ、いよいよ「認証プラグイン」をインストールするわよ
composer require "cakephp/authentication:^2.0"[Enter] |
ではなく
composer require cakephp/authentication[Enter] |
だからね


C菜
えっと、次は「パスワードハッシュの追加」ですね~
「src/Model/Entity」の中にある「User.php」を修正するです~
まずは「$_accessible」フィールドを修正して~
protected array $_accessible = [
'*' => true, 'id' => false ]; |
あと「_setPassword」メソッドを追加します~
protected function _setPassword($password)
{ if (strlen($password) > 0) { return (new DefaultPasswordHasher)->hash($password); } } |
あ、先頭に次の一文を追加するのを忘れずに~
use Cake\Auth\DefaultPasswordHasher; |



A子
えーっと
「src」ディレクトリの中にある「Application.php」を修正するんだね?
(基本的に公式サイトからのコピペだから、ソースコードは省略ね)






C菜


B美
$this->loadComponent('RequestHandler'); |
の一文は挿入しないでね
(エラーになるから…)


A子
まぁ、気を取り直して…
次は「src/Controller」の中にある「UsersController.php」に三つのメソッドを追加すれば良いんだね



A子
ログイン後に表示されるページは「article」じゃなくて「top」にしたよ
なのでbakeコマンドで「TopController」を作ります
bin/cake bake controller top[Enter] |
あと、「templates」の中に「Top」ディレクトリを作って、その中に「index.php」も作っておこう
(中身の無い空ファイルだけど…)


C菜
(ログインページです~)


A子
さて、うまく動くかな?
ブラウザのURL欄には「http://(IPアドレス)/authapp」を入れてっと…
(ドキドキ)
…って、あれ?
うまくいかない…

B美
リダイレクト先が「Webサーバのドキュメントルートを基点とした絶対パスになっている」から、うまくいかないのよ
もっとも簡単な解決策としては「/users/login」の箇所(二ヶ所あります)を「/authapp/users/login」に変更することなんだけど、もっとスマートな方法としては下記になるわね
(Routerクラスのurlメソッドを用いる方法)
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{ $authenticationService = new AuthenticationService([ 'unauthenticatedRedirect' => Router::url([ 'prefix' => false, 'plugin' => null, 'controller' => 'Users', 'action' => 'login', ]), 'queryParam' => 'redirect', ]); // 識別子をロードして、電子メールとパスワードのフィールドを確認します $authenticationService->loadIdentifier('Authentication.Password', [ 'fields' => [ 'username' => 'email', 'password' => 'password', ] ]); // 認証子をロードするには、最初にセッションを実行する必要があります $authenticationService->loadAuthenticator('Authentication.Session'); // メールとパスワードを選択するためのフォームデータチェックの設定 $authenticationService->loadAuthenticator('Authentication.Form', [ 'fields' => [ 'username' => 'email', 'password' => 'password', ], 'loginUrl' => Router::url([ 'prefix' => false, 'plugin' => null, 'controller' => 'Users', 'action' => 'login', ]), ]); return $authenticationService; } |
あ、先頭には以下の一文を必ず追加してね
use Cake\Routing\Router; |






C菜


A子
ユーザを新規作成するために「Add User」をクリックしてみたんだけど、ユーザ登録のページが表示されない…
なんでだ?

B美
(自分でコードを打ち込んでおいて…)
「src/Controller」の「UsersController.php」の「beforeFilter」メソッドだけど…
$this->Authentication->addUnauthenticatedActions(['login']); |
の箇所って、「login」だけは認証なしで表示できるって意味なのよ
(つまり、「login」以外は認証必須ってこと)

A子
てか、わかったよ
「add」メソッドをその配列要素に追加すれば良いんじゃない?
$this->Authentication->addUnauthenticatedActions(['login', 'add']); |
ありゃ?
今度はこんなエラーが出たよ


B美
そこを「notEmptyString」に変更してね
public function validationDefault(Validator $validator): Validator
{ return $validator ->notEmptyString('email', 'A email is required') ->email('email') ->notEmptyString('password', 'A password is required'); } |


A子
公式ページがあてにならねぇ!(怒)
と、とにかく…
修正したら、ユーザ登録のページを表示することができたよ


C菜
あれ~?
またもやエラーになりましたよ~


B美
「_setPassword」メソッドについては、以下のように書き換えてほしいのよ
(先頭のuseの部分も一緒に…)
use Authentication\PasswordHasher\DefaultPasswordHasher; |
protected function _setPassword($password)
{ if (strlen($password) > 0) { $hasher = new DefaultPasswordHasher(); return $hasher->hash($password); } } |
これもまた、公式があてにならない…ってパターンなんだけどね(苦笑)



A子
今度は(エラーが出ることなく)ユーザ登録できたよ
あ、さっきの
$this->Authentication->addUnauthenticatedActions(['login', 'add']); |
だけど
$this->Authentication->addUnauthenticatedActions(['login']); |
に戻しておいたほうが良いんだよね?

B美
一人でもユーザが存在すれば、そのユーザでログインすることで後は何人でもユーザを増やせるからね
ただし、セキュリティ面を考えると、「ユーザ管理ページにアクセスできるのは、BASIC認証を通った管理者のみ」にしておくほうが良いと思うわよ
さて、あとは公式ページと実際のコーディングについての差異をまとめておきましょうか
【総まとめ】
・composerでauthenticationをインストールする際、バージョンを指定しない
・$this->loadComponent('RequestHandler');は記述しない ・リダイレクト先のURLはRouterクラスを使って作成する ・ValidatorクラスのnotEmptyはnotEmptyStringに変更する ・DefaultPasswordHasherのパスは(Cake\Authではなく)Authentication\PasswordHasherとする |

C菜

A子
まぁ、うちにはB美がいるから大丈夫だけどね

C菜
あ、あとログインページをちょっと修正してみました~
(「Add User」のリンクは削除)

↓


A子
(「新規ユーザ登録」をこっちに移動させて、「ログアウト」のリンクも作ったよ)

↓


B美
ただ、Bulma(CSSフレームワーク)を組み込んだり、本格的に体裁を整えていくのは次回にしましょう

C菜

A子
単なるサンプルだから適当な名前(authapp)にしたんだけど、ここからこれをベースにしてなんか作っていくの?

B美
まぁ、なんにせよ見栄えは大事じゃん(笑)