CakePHP 4x: AuthenticationMiddleware の挙動と、ログイン時に毎回From認証するサンプル

AuthenticationMiddleware の挙動が把握できておらず、ハマったのでメモ

AuthenticationMiddleware の挙動

チュートリアル

// src/Application.php

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        // 〜
        ->add(new AuthenticationMiddleware($this));

    // 〜
}

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    // 〜

    $authenticationService->loadAuthenticator('Authentication.Session');
    $authenticationService->loadAuthenticator('Authentication.Form', [
        // 〜
    ]);

    // 〜
}
// UsersController

public function login()
{
    // 〜 略 〜

    $result = $this->Authentication->getResult();

    // 〜 略 〜
}

このようなサンプルがあるが、getResult() までの流れはこのようになっている

  • getResult() の Result はミドルウェアの段階でセットされる
  • AuthenticationMiddlewareSessionAuthenticator -> FormAuthenticator の順で認証して、認証できた時点で Result が Success になる
  • ログイン中は FormAuthenticator は実行されない (username + password による認証は行われない)

今回やりたかった事

  • ログイン中であっても username + password による再認証を行いたい

実現方法

  • login アクション内 で FormAuthenticator を取得して username + password による認証を行う

サンプル

public function login()
{
    /** @var AuthenticationComponent $authenticationComponent */
    $authenticationComponent = $this->Authentication;

    // 既存のセッションを削除
    $authenticationComponent->logout();

    /** @var AuthenticationService $authenticationService */
    $authenticationService = $authenticationComponent->getAuthenticationService();
    $authenticators = $authenticationService->authenticators();

    // FormAuthenticator を取得
    $formAuthenticator = null;
    foreach ($authenticators as $authenticator) {
        if ($authenticator instanceof FormAuthenticator) {
            $formAuthenticator = $authenticator;
        }
    }
    if (is_null($formAuthenticator)) {
        throw new \Exception();
    }

    // FormAuthenticator で username + password による認証を行い、セッションを生成
    /** @var FormAuthenticator $formAuthenticator */
    $authenticate = $formAuthenticator->authenticate($this->_request());
    if (!$authenticate->isValid()) {
        // 適宜
    }
    $authenticationComponent->setIdentity($authenticate->getData());

    // 〜
}