CakePHP : Utiliser un service d’authentification différent suivant le prefix

La base

Dans une application CakePHP, vous pouvez avoir une partie “front” qui ne nécessite pas d’authentification, contrairement à la partie “backend”.

Le “backend” peut être configuré à l’aide de prefix de route comme documenté ici

Le plus simple est de configuré le plugin cakephp/authentication dans votre src/Application.php en ajoutant le plugin, le middleware et la configuration du service dans Application::getAuthenticationService()
Ensuite, il suffit d’ajouter, dans votre App\Controller\BackendController::initialize() :

public function initialize(): void
{
    parent::initialize();

    $this->loadComponent('Authentication.Authentication');
]

Et le tour est joué.

Plus de complexité

(short english explanation on cakephp forum)

On peut être amené à avoir une partie du site qui utilise un FormAuthenticator alors qu’une autre partie va utiliser un HttpDigest ou Token. Dans ce cas, voici une solution, un peu plus complexe mais qui est aussi plus souple.

Dans le fichier config/routes.php :

$routes->prefix(
    'Backend',
    ['path' => '/gestion', '_namePrefix' => 'backend:'],
    function (RouteBuilder $builder) {
        $authenticationService = new AuthenticationService();
        $fields = [
            IdentifierInterface::CREDENTIAL_USERNAME => 'email',
            IdentifierInterface::CREDENTIAL_PASSWORD => 'password',
        ];
        $authenticationService->loadAuthenticator(SessionAuthenticator::class);
        $authenticationService->loadAuthenticator(FormAuthenticator::class, [
            'fields' => $fields,
            'urlChecker' => '\Authentication\UrlChecker\CakeRouterUrlChecker',
            'loginUrl' => ['_name' => 'backend:auth:login'],
        ]);
        $authenticationService->loadIdentifier(PasswordIdentifier::class, [
            'fields' => $fields,
        ]);
        $builder->registerMiddleware('authentication', new AuthenticationMiddleware($authenticationService));
        $builder->applyMiddleware('authentication');

Dans le fichier Application::bootstrap() :

$this->addPlugin('Authentication');

Et ensuite dans le Controller de votre prefix :

public function initialize(): void
{
    parent::initialize();

    $service = $this->request->getAttribute('authentication');
    $service->setConfig([
        'unauthenticatedRedirect' => Router::url(['_name' => 'backend:auth:login']),
        'queryParam' => 'r',
    ]);

    $this->loadComponent('Authentication.Authentication');
}

Désormais, ce prefix va utiliser le service d’Authentification que vous avez configuré dans votre fichier de routes. Et vous pouvez en configurer 1 par prefix, sans limitation.