cakePHPはバージョンが5まで上がっていて、そろそろ普段開発に使っていたcakePHP4から勉強のために触ろうと思い、今回は管理画面を作ってみることにしました。

ひとまずはcakePHP4と同じような構築を試してみようと公式ドキュメントを参考にチコチコとプログラミンしていってみると案の定色々と躓いてしまったので、画面遷移が上手く行った段階ですがとりあえず忘れないように記録として残しておきます。

まず、cakePHP4の通りに構築してみて表示したエラーはAuthComponentの事でした。

 

AuthComponent could not be found.

 

そもそもすでにcakePHP4では非推奨だったのですが、推奨していた公式ドキュメント通りにやってもエラーが発生し解決全くできなかったために、AuthComponentを使用して管理画面を構築していました。

恐らくcakePHP5からは出来なくなったのでしょう。

その為、今回は別の方法で構築をチャレンジしてみました。(ドキュメント通りのやり方ですがw)

 

開発環境としてはXAMPPのhtdocs内にディレクトリを作って、その中にcakePHP5をインストールしての開発で、ログイン画面はAdminという管理画面用のディレクトリをつけたURLにしたい

 

【通常】
http://localhost/hoge

【管理画面】
http://localhost/hoge/admin/user/login

 

構築の方法はドキュメントを参考に以下のようなやり方です。

 

公式ドキュメント参考ページ「シンプルな認証と認可のアプリケーション」
https://book.cakephp.org/5/ja/tutorials-and-examples/blog-auth-example/auth.html

 

1.DBにユーザー用のテーブルを作成。カラムにusernameとpasswordを用意。

2.Model、Controller、Templateをbakeで生成。

 

ここまでは普段通りで特に何もしていません。次からが認証機能の追加、構築となります。

 

3.認証の追加のコマンドを入力しインストール

 

composer require "cakephp/authentication:^2.0"

 

ここでエラーが発生しました。

 

Your requirements could not be resolved to an installable set of packages.
Installation failed, reverting ./composer.json and ./composer.lock to their original content.

 

調べてみるとauthenticationのバージョンが対応してないとのような情報があがっていました。試しにコマンド後にある数字を抜いてコマンド入力してみると、今の対応バージョンが表示されました。この記事現在では3.2.1でした。その為以下のように変更して再入力。

 

composer require "cakephp/authentication:^3.2"

 

これはすんなり通りダウンロード開始してインストール完了しました。

 

4.パスワードハッシュの追加

 

// src\Moder\Entity\User.phpに追加

use Cake\Auth\DefaultPasswordHasher;

protected function _setPassword($password)
{
  if (strlen($password) > 0) {
    return (new DefaultPasswordHasher)->hash($password);
  }
}

 

5.認証の設定

 

// src/Application.phpに追加

// 認証用
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ServerRequestInterface;




// BaseApplication の後に文字を追加
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{




// middlewareの中身に任意の文字を追加
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
  $middlewareQueue
  ****
    ->add(new RoutingMiddleware($this))

    // この辺りに追加
    ->add(new AuthenticationMiddleware($this))

  ****
  return $middlewareQueue;
}

// 新たにfunctionを追加

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
  $authenticationService = new AuthenticationService([
    'unauthenticatedRedirect' => '/users/login',
    'queryParam' => 'redirect',
  ]);

  // 識別子をロードして、電子メールとパスワードのフィールドを確認します
  $authenticationService->loadIdentifier('Authentication.Password', [
    'fields' => [
      'username' => 'username',
      'password' => 'password',
    ]
  ]);

  // 認証子をロードするには、最初にセッションを実行する必要があります
  $authenticationService->loadAuthenticator('Authentication.Session');
  // メールとパスワードを選択するためのフォームデータチェックの設定
  $authenticationService->loadAuthenticator('Authentication.Form', [
    'fields' => [
      'username' => 'username',
      'password' => 'password',
    ],
    'loginUrl' => '/users/login',
  ]);
  return $authenticationService;
}

 

// AppController.phpに認証用を追加

public function initialize(): void
{
  parent::initialize();
  $this->loadComponent('RequestHandler');
  $this->loadComponent('Flash');

  // Add this line to check authentication result and lock your site
  $this->loadComponent('Authentication.Authentication');
}

 

// UserController.phpにlogin()とlogout()のfunctionを追加

public function beforeFilter(\Cake\Event\EventInterface $event)
{
  parent::beforeFilter($event);
  // ログインアクションを認証を必要としないように設定することで、
  // 無限リダイレクトループの問題を防ぐことができます
  $this->Authentication->addUnauthenticatedActions(['login']);
}

public function login()
{
  $this->request->allowMethod(['get', 'post']);
  $result = $this->Authentication->getResult();
  // POSTやGETに関係なく、ユーザーがログインしていればリダイレクトします
  if ($result->isValid()) {
    // ログイン成功後に /article にリダイレクトします
    $redirect = $this->request->getQuery('redirect', [
      'controller' => 'Users',
      'action' => 'index',
    ]);

    return $this->redirect($redirect);
  }
  // ユーザーの送信と認証に失敗した場合にエラーを表示します
  if ($this->request->is('post') && !$result->isValid()) {
    $this->Flash->error(__('Invalid username or password'));
  }
}

public function logout()
{
  $result = $this->Authentication->getResult();
  // POSTやGETに関係なく、ユーザーがログインしていればリダイレクトします
  if ($result->isValid()) {
    $this->Authentication->logout();

    return $this->redirect(['controller' => 'Users', 'action' => 'login']);
  }
}

 

これでブラウザで確認してみると色々とエラーが表示しましたので、それを一つずつ解決していきました。

 

RequestHandlerComponent could not be found.
Create the class RequestHandlerComponent below in file: src\Controller\Component\RequestHandlerComponent.php

 

AppController.phpのinitialize()内にあるComponentの一つなんですが、これは要らないんだそうですw

その為、削除でエラーは消えました。

 

Not Found

 

URLを確認すると、以下のようになっていて存在しないページを指していました。

 

http://localhost/users/login?redirect=

 

Application.php に追加したfunctionのunauthenticatedRedirectで設定しているパスに認可されてない場合のリダイレクト先になるようですが、管理画面用のディレクトリ名も追加しておくべきのところ、頭にスラッシュがついてるためXAMPPではドキュメントルート指してしまうためにインストールしたディレクトリより上に行ってしまった模様です。

本来ならcakePHPの簡易サーバー起動させればこういうことはならなかったんでしょう。こちらのミスですので、ひとまずは強制的にディレクトリ名を追加してごまかします。

 

'unauthenticatedRedirect' => '/users/login',
↓
'unauthenticatedRedirect' => '/hoge/admin/users/login',

 

これでひとまずログイン画面は表示できましたが、ユーザーがいなければログインテストできませんw

ここで追加するテストも兼ねてテストユーザーを作成してみることに。すると、エラーが発生しました。

 

Class "Cake\Auth\DefaultPasswordHasher" not found

 

えーー!?これはどうなの?

と驚いてしまいました。公式ドキュメントに載ってる情報でこのエラーはちょっと…

 

ネットで色々と調べたら海外でも同じようなエラーで質問されてたりしていて、これに対する回答がいくつかあり、試してみるとエラーが解消されました。ホントすごい人はたくさんいますね。

解決方法としては、ModelのUser.phpのuse部分のインポートとfunctionの_setPassword()部分を変更します。

 

use Cake\Auth\DefaultPasswordHasher;
↓
use Authentication\PasswordHasher\DefaultPasswordHasher;

return (new DefaultPasswordHasher)->hash($password);
↓
$hasher = new DefaultPasswordHasher();
return $hasher->hash($password);

 

これに変更し、無事ユーザーが追加されました。パスワードはハッシュ化されて複雑化されていました。

私のように公式ドキュメント通りにしたのに上手くいかなかった人は多くいたことでしょう。しかし、その分解決してきた人も多くいて、大変勉強になり助かりました。

 

次はログイン認証して無事ログインできるかのテストです。

が、時間がなく今回はここまでということで。