[CakePHP4.x]複数認証の実装方法

CakePHP4で認証システムを実装するのは若干以前より面倒になった感があります。
通常の実装方法に関しては、こちらで以前記事にしました。
一般的な実装方法についてわからない場合はcakebookの下記のページを参照すればよいかと思います。

今回は、複数の認証システムを実装する方法を紹介したいと思います。
よく使うのは、一般ユーザーが使う表ページ用のログイン画面と、adminルーティングを使ってサイトの管理用のページ用のログイン画面の2つを実装したい場合に使います。

昔のバージョン

以前のバージョン(CakePHP3以前)の古い認証コンポーネントの場合は、セッションキーを変えることで、簡単に認証システムを切り替えることができました。
具体的には・・・

$this->Auth->sessionKey = 'Auth.User';
$this->Auth->sessionKey = 'Auth.AdminUser';

ログイン情報はセッションに保存されますが、こんな感じで、コントローラーやアクションごとに読み書きするセッションを切り替えることで、複数の認証システムを表現できました。

Authentication Component 2.xの場合

まず、2種類の認証システムの設定をそれぞれの場合で設定しなければなりません。
こちらの方法については、CakeBookの方に乗っていました。

//Applicathion.php の中で・・。
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    $path = $request->getPath();

    $service = new AuthenticationService();
    if (strpos($path, '/api') === 0) {
        // Accept API tokens only
        $service->loadAuthenticator('Authentication.Token');
        $service->loadIdentifier('Authentication.Token');

        return $service;
    }

    // Web 認証
    // サポートセッションとフォームログイン
    $service->loadAuthenticator('Authentication.Session');
    $service->loadAuthenticator('Authentication.Form');

    $service->loadIdentifier('Authentication.Password');

    return $service;
}

サンプルの例はそもそも認証方法がそれぞれ違うので、若干何をやっているのかわからない感じですが、ポイントとしては$requestからパスなどを調べて、パスに合った設定をしてあげるということのようです。
以前のバージョンはコントローラー側で設定できたのですが、Authentication 2.xの場合はApplicathion.phpの中で全部やらないといけないみたいで、若干自由度が減った気がします。
それはさておき、これだけではやりたいことは実現できていません。
というのも、この情報だけだと、例えば表画面でログインできたとして、管理画面に行ってもログインが済んでいることになっていて管理画面が見えちゃうんです。
ログイン情報自体はセッションに保存されていますが、ただ単に認証情報のセッション情報があるかないかでログインの状態かどうか見ているだけなので、この設定を変えただけだとどちらかでログインできたら両方見えてしまうというわけです。
以前のバージョンと同じようにセッション名の切り替えが必要なんですが…これが書いてない。
というわけでいろいろ調べて方法を見つけました。
こんな感じで書くとセッションキーが変更できるようです

$service = new AuthenticationService();
$service ->loadAuthenticator('Authentication.Session', [
    sessionKey' => 'Auth.User',
]);

具体的な書き方を記載します
表画面の設定は
モデル名はUsers
ログインURLは/users/login
2つ目の認証は管理画面を想定してprefixにadminをつけて
モデル名はAdminUsers
ログインURLはadmin/adminusers/login

そのほかカラム名などはすべてデフォルト設定ということにします
という想定にします。

//Applicathion.php の中で・・
$path = $request->getPath();
$service = new AuthenticationService();
//adminルーティング用の設定
if (strpos($path, '/admin') === 0) {
   $authenticationService = new AuthenticationService([
   unauthenticatedRedirect' => '/admin/adminusers/login',  //リダイレクト先
   'queryParam' => 'redirect',
   ]);
   $authenticationService->loadIdentifier('Authentication.Password', [
       'resolver'=>[
        'userModel' => 'AdminMembers',//認証用のモデル名を変更
  ]);
  $service ->loadAuthenticator('Authentication.Session', [
    'sessionKey' => 'AdminUser', //認証情報を保存するセッションキーの変更
  ]);
  $authenticationService->loadAuthenticator('Authentication.Form', [
   'loginUrl' => '/admin/adminusers/login', //ログインページの登録
  ]);
  return $service;
}
//一般ユーザー用の設定
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form');
$service->loadIdentifier('Authentication.Password');
return $service;

そのほかの部分は通常の場合の書き方で大丈夫です。

ポイントは’Authentication.Sessionでセッションキーを変更する必要があります。
デフォルトのセッションキー名はAuthになりますので、もう片方は別の名前にする必要があります。

参考までに、セッションキーをAuthとAuth.Admin にしたところ、バグってログインできなくなってしまいました。
さんざん悩んだ挙句、Auth.Adminみたいな形にすると(たぶん)セッションに保存されるデータの形式が変わってしまって動かなくなるようです。ログやデバッガでみても空にしか見えないので問題ないはずと思ったのですが、セッションを全削除したら治りましたが、セッションキーは配列構造にしないほうがいいみたいです。

タイトルとURLをコピーしました