Top View


Author uchida

CakePHP4 x Authentication でマルチログイン(複数認証)を作る

2021/09/09

やりたいこと

  • 管理者
    • Table : Administrators
    • url : localhost/admin
  • ユーザ
    • Table : Users
    • url : localhost/user

上記の状態で、それぞれのURLにはぞれぞれのTableに存在するレコードで認証をするようにします。

やってみる

src/Application.phpAuthentication プラグインを読み込みます。

public function bootstrap(): void
{
    parent::bootstrap();
    ....
    // 末尾に追記
    $this->addPlugin('Authentication');
}

通常のやり方だと、このあと src/Application.php の中で、middlewareに登録したり、 getAuthenticationService したりします。
もちろんこの方法でも ifの分岐などでマルチログインは出来るのですが、個人的にどのrouteにどの認証が適用されているのか分かりにくく感じます。
Configuring Multiple Authentication Setups

今回は routes.php に認証の設定を記述する方式を紹介します。
prefixごとに認証の設定を記述できるので、少々冗長な書き方になりますが、分かりやすくて好きです。

<?php
use App\Middleware\AccessControlMiddleware;
use Authentication\AuthenticationService;
use Authentication\Middleware\AuthenticationMiddleware;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;

#----------------------------------------------------------------------------
# Routing

/** @var \Cake\Routing\RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);

/**
 * 管理者用のルーティング
 */
$routes->prefix('Admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) {

    #----------------------------------------------------------------------------
    # 認証の設定

    $adminAuth = new AuthenticationService([
        'unauthenticatedRedirect' => '/admin/auth/login',
        'queryParam' => 'redirect',
    ]);

    $adminAuth->loadIdentifier('Authentication.Password', [
        'fields' => [
            'username' => 'email',
            'password' => 'password',
        ],
        'resolver' => [
            'className' => 'Authentication.Orm',
            'userModel' => 'Administrators',
        ],
    ]);

    $adminAuth->loadAuthenticator('Authentication.Session', [
        'sessionKey' => 'admin',
    ]);

    $adminAuth->loadAuthenticator('Authentication.Form', [
        'fields' => [
            'username' => 'email',
            'password' => 'password',
        ],
        'loginUrl' => '/admin/auth/login',
    ]);

    $routes->registerMiddleware('admin-auth', new AuthenticationMiddleware($adminAuth));
    $routes->applyMiddleware('admin-auth');

    #----------------------------------------------------------------------------
    # ルーティング

    // ダッシュボード
    $routes->get('/', ['controller' => 'Dashboard', 'action' => 'top'], 'dashboard:top');
});

/**
 * ユーザ用のルーティング
 */
$routes->prefix('User', ['_namePrefix' => 'user:'], function (RouteBuilder $routes) {

    #----------------------------------------------------------------------------
    # 認証の設定

    $userAuth = new AuthenticationService([
        'unauthenticatedRedirect' => '/user/auth/login',
        'queryParam' => 'redirect',
    ]);

    $userAuth->loadIdentifier('Authentication.Password', [
        'fields' => [
            'username' => 'email',
            'password' => 'password',
        ],
        'resolver' => [
            'className' => 'Authentication.Orm',
            'userModel' => 'Users',
        ],
    ]);

    $userAuth->loadAuthenticator('Authentication.Session', [
        'sessionKey' => 'user',
    ]);

    $userAuth->loadAuthenticator('Authentication.Form', [
        'fields' => [
            'username' => 'email',
            'password' => 'password',
        ],
        'loginUrl' => '/user/auth/login',
    ]);

    $routes->registerMiddleware('user-auth', new AuthenticationMiddleware($userAuth));
    $routes->applyMiddleware('user-auth');

    #----------------------------------------------------------------------------
    # ルーティング

    // ダッシュボード
    $routes->get('/', ['controller' => 'Dashboard', 'action' => 'top'], 'dashboard:top');
});

本来は src/Application.php でやっている Middlewareの登録と AuthenticationServiceの定義を routes.php でやっています。
こちらの方式であれば、 /api が増えたときなども prefix ごとに別途定義を出来るので、 Application.php でif文が増えるようなことにはなりません。

ここまで定義が出来れば、あとはそれぞれの Prefix に対応するNamespace以下にチュートリアルと同様のログイン用のControllerやtemplateを設置すればOKです。

おわり

最近はLaravelばかりだったので、CakePHPのリハビリを継続中です。
CakePHP3の初期のころと変わっている点も多いのですが、確実に使いやすくなっていて触っていて楽しいです。

uchida

uchida

福岡でWebエンジニアやってます。PHP, クラウド, インフラあたりが好き。AWS 五冠