Friction River Software

  • お問い合わせ

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

A子

登録した会員だけが閲覧できるWebサイトってさー
ログイン認証の機能を作らないとダメじゃん

それって簡単に作れるものなの?

B美

CakePHP5だったら割と簡単に作れるわよ

C菜

公式サイトにも「認証プラグイン」って記述がありましたよ~
(クリックすると別ウィンドウで開きます)

B美

あー、それなんだけどさ

認証に関してはこっちのページを見てほしいのよね
(クリックすると別ウィンドウで開きます)

A子

ちょっ、英語じゃん
(公式ページなのは同じだけど…)

C菜の示した日本語のページのほうが良いんだけど…

C菜

あっ!
バージョンが違いますよ~

B美

C菜、正解!
最新バージョンである「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美

OKよ

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

A子

えっと、プロジェクト名は「authapp」にしておこうかな
(超・適当(笑))

cd html[Enter]
composer create-project --prefer-dist cakephp/app authapp[Enter]

もちろん、途中で止まったら「Y」を入力して[Enter]キーだね



C菜

ModelモデルControllerコントローラーのファイルをbakeコマンドで作っても良いでしょうか~?

A子

良いんじゃない?
(面倒だし…)

cd authapp[Enter]
bin/cake bake all users[Enter]

で良いんだよね?

B美

ちょーっと待ったぁ!
先に「config」ディレクトリの中の「app.php」と「app_local.php」を修正しておきなさいね

でないと、bakeコマンドが通らない(エラーになる)わよ

A子

おっと、そうだった…(苦笑)

ん?何行目だったっけ?

C菜

app.php」の52行目、53行目、285行目と、「app_local.php」の47行目、48行目、50行目ですよ~

A子

書き換えたよー
もはや慣れたもんだね

んじゃ、あらためて…

cd authapp[Enter]
bin/cake bake all users[Enter]



C菜

公式サイトにしたがって、「src/Model/Table」の中にある「UsersTable.php」の「validationDefault」メソッドを書き換えましょう~

あ~、ただし…
データベーステーブルから「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子

んじゃ、次は「UsersController.php」だね
(さっき「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菜

あとは「src/Controller」の中にある「AppController.php」を修正するです~

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菜

最後に「templates/Users」の中に「login.php」を新規作成します~
(ログインページです~)

A子

これで公式ページの手順通りに全て終わったよ
さて、うまく動くかな?

ブラウザのURL欄には「http://(IPアドレス)/authapp」を入れてっと…
(ドキドキ)

…って、あれ?
うまくいかない…

B美

「src」ディレクトリの中にある「Application.php」というファイルの「getAuthenticationService」メソッドなんだけどさー
リダイレクト先が「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菜

修正後、再度「http://(IPアドレス)/authapp」にアクセスしてみたら、きちんとログインページが表示されました~

A子

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

なんでだ?

B美

「なんでだ?」じゃないわよ(苦笑)
(自分でコードを打ち込んでおいて…)

「src/Controller」の「UsersController.php」の「beforeFilter」メソッドだけど…

$this->Authentication->addUnauthenticatedActions(['login']);

の箇所って、「login」だけは認証なしで表示できるって意味なのよ
(つまり、「login」以外は認証必須ってこと)

A子

いや、公式ページからコピペしただけだし…(汗)

てか、わかったよ
「add」メソッドをその配列要素に追加すれば良いんじゃない?

$this->Authentication->addUnauthenticatedActions(['login', 'add']);

ありゃ?
今度はこんなエラーが出たよ

B美

「src/Model/Table」の「UsersTable.php」の「validationDefault」メソッドの中に「notEmpty」って箇所があるわよね?
そこを「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美

「src/Model/Entity」の中にある「User.php」なんだけどさー

_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とする
※2025年3月時点(将来、公式ページが修正される可能性はあります)

C菜

これって公式ページを修正してくれないと、認証関係で挫折する人が続出しそうです~

A子

ほんとだよ(苦笑)

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

C菜

ですね~

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



A子

それじゃ、ログイン認証後のトップページも作っちゃおう
(「新規ユーザ登録」をこっちに移動させて、「ログアウト」のリンクも作ったよ)



B美

ふむ、良い感じね

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

C菜

了解で~す

A子

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

B美

いや、どうなるか分からないけどね

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