綺麗に死ぬITエンジニア

CakePHP3でプレフィックスルーティングを利用した複数認証を実装する

2018-11-02

複数の独立した認証処理を導入したWebアプリケーションをCakePHPを使って実装する方法を紹介します。

CakePHPではプレフィックスルーティングと組み合わせることで、効率的に認証の仕組みを振り分けることができます。

本記事では、CakePHP 3のインストールから、プレフィックスルーティングを利用した複数認証の実装まで、解説します。

CakePHP 3のインストール

通常どおり、以下のコマンドでCakePHP 3をインストールします。

composer create-project --prefer-dist cakephp/app my_app_name

インストールできたら、確認用の開発サーバーを起動します。

cd my_app_name
bin/cake server

http://localhost:8765/へアクセスし、アプリケーションが正常に動作していることを確認します。

プレフィックスルーティングの定義

以下のように、別々の認証が必要なまとまりをプレフィックスルーティングでまとめます。

<?php
// config/routes.php

use Cake\Routing\Route\DashedRoute;

// 認証1
Router::prefix('admin', function (RouteBuilder $routes) {
    $routes->fallbacks(DashedRoute::class);
});

// 認証2
Router::prefix('member', function (RouteBuilder $routes) {
    $routes->fallbacks(DashedRoute::class);
});

// 認証3
Router::prefix('user', function (RouteBuilder $routes) {
    $routes->fallbacks(DashedRoute::class);
});

上記のようにして、/admin/配下、/member/配下、/user/配下でそれぞれ別の認証が必要となるような実装を行います。

プレフィックスルーティングにより、それぞれのプレフィックスで参照するコントローラーの場所が変わります。

例えば、上記の定義の場合、/admin/users/edit/5へアクセスしたとき、src/Controller/Admin/UsersController.phpedit()メソッドが呼ばれ、ビューファイルはsrc/Template/Admin/Users/edit.ctpになります。

同様に、/member/dashboardは、src/Controller/Member/DashboardController.phpindex()メソッドが呼ばれ、ビューファイルはsrc/Template/Member/Dashboard/index.ctpといった感じです。

src/Controllerおよびsrc/Templateにプレフィックス用のディレクトリを追加して、そこにコントローラーやビューテンプレートをまとめる、といったディレクトリ構成とルーティングになります。

このとき、ディレクトリ構成とともに、作成したコントローラーの名前空間も変わりますので、忘れないように変更しましょう。

<?php

namespace App\Controller\Admin;  // <- 変更

class UsersController extends AppController {}

プレフィックス毎にAppControllerを定義する

プレフィックス毎に認証処理を分けて実装するために、プレフィックスのディレクトリにAppControllerを用意し、各プレフィックス配下のコントローラーはそのAppControllerを継承するようにします。

例えば、src/Controller/Admin/AppController.phpを以下の内容で配置します。

<?php

namespace App\Controller\Admin;

class AppController extends \App\Controller\AppController
{
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'userModel' => 'Administrators',
                ],
            ],
            'storage' => ['className' => 'Session', 'key' => 'Auth.Admin'],
        ]);
    }
}

こうすることで、このAppControllerを継承したsrc/Controller/Admin/配下のコントローラーは、administratorsテーブルの情報でのログインが必要になります。

同様に、MemberUserプレフィックスでもAppControllerを定義しましょう。

<?php
// src/Controller/Member/AppController.php

namespace App\Controller\Member;

class AppController extends \App\Controller\AppController
{
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'userModel' => 'Members',
                ],
            ],
            'storage' => ['className' => 'Session', 'key' => 'Auth.Member'],
        ]);
    }
}
<?php
// src/Controller/User/AppController.php

namespace App\Controller\User;

class AppController extends \App\Controller\AppController
{
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'userModel' => 'Users',
                ],
            ],
            'storage' => ['className' => 'Session', 'key' => 'Auth.User'],
        ]);
    }
}

これで、/admin/以下はadministratorsテーブル、/member/以下はmembersテーブル、/user/以下はusersテーブルを使って認証する仕組みになりました。

一つ注意すべき点として、AuthComponentstorage.keyはそれぞれの認証で一意の値である必要があります。通常、上の例のように'Auth.[プレフィックス名]'とするのがいいでしょう。

storage.keyを一意の値にすることで、各認証が独立して動くようになるため、複数の認証で同時にログインしたりすることができるようになります。

その後の実装

ここまでで、最終的に以下のような構成になりました。

src/Controller
├── Component
│   └── empty
├── Admin
│   └── AppController.php
├── Member
│   └── AppController.php
├── User
│   └── AppController.php
├── AppController.php
├── ErrorController.php
└── PagesController.php

後は、それぞれのプレフィックスディレクトリ(src/Controller/Admin/src/Controller/Member/src/Controller/User/)の下に、それぞれのAppControllerを継承したコントローラーを作成し、開発を進めていきましょう。

なお、それぞれ作成するプレフィックスディレクトリ配下のコントローラーは、プレフィックスディレクトリのAppControllerと同じ名前空間になりますので、継承する際にはuse演算子を使わずに単純に以下のように書くだけでOKです。

<?php

namespace App\Controller\Admin;

class UsersController extends AppController {}

そして、参照するビューファイルはそれぞれsrc/Template/Admin/src/Template/Member/src/Template/User/の下にいつも通り作ればOKです。

ログインやログアウト等の処理については、プレフィックスの配下で普段と同様に実装すれば問題ありません。CakePHPのドキュメントにて解説されていますので、そちらを参考にしてください。

まとめ

以上、CakePHP 3で複数の独立した認証処理を実装する方法を解説しました。

本記事ではプレフィックスルーティングを活用して管理しやすいように実装しましたが、同様の仕組みを実装すればプレフィックスルーティングなしでも実装可能かと思います。

もしCakePHPで複数の認証処理が必要な場面に出くわしましたら、ぜひ参考になさってください。

筆者について

「もりやませーた」として活動している、フリーランスエンジニアです。1992年生まれ、神奈川県在住、既婚。

筆者のTwitterはこちら。記事に関するご意見等はTwitterの方へお寄せください。

その他業務に関するお問い合わせは、こちらのページをご覧ください。

PHP セキュリティ