CakePHP3のAuthコンポーネントで、identify()のFindの挙動をカスタマイズする方法

<前提条件>CakePHP(3.6), MySQL(5.7.22)

例えばMySQLのusersテーブルが下記の構成だったとする:

CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `email` varchar(255) NOT NULL,
 `password` varchar(255) NOT NULL,
 `deleted` int(1) NOT NULL DEFAULT '0',
 `nickname` varchar(255) DEFAULT NULL,
 `profile` text,
 `created` datetime DEFAULT NULL,
 `modified` datetime DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `idx_users_01` (`nickname`),
 KEY `idx_users_02` (`email`,`password`),
 KEY `idx_users_03` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

deletedというカラムがミソで、値が0ならログインできて1なら退会済という意味で使っているケースを前提とする。この場合、ログイン認証をパスする際はemail, passwordが入力された値に合致し、且つdeleted=0であればログインできるという実装にしたい。

通常、Authコンポーネントのidentify()ではemailとpasswordのみを使って認証を行うように作る例が多い。つまり、こちらが今回準備したdeletedのようなカスタマイズに対応させる必要がある。

結論:finderオプションを使って解決できる

参照:検索クエリーのカスタマイズ

参照を基に実際コードを書くとこんな感じ:

src/Controller/AppController:

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

        $this->loadComponent('RequestHandler', [
            'enableBeforeRedirect' => false,
        ]);
        $this->loadComponent('Flash');

        $this->loadComponent('Auth', [
            'authorize'=> 'Controller',
            'authenticate' => [
                'Form' => [
                    'fields' => [
                        'username' => 'email',
                        'password' => 'password'
                    ],
                   'finder' => 'auth' // ←の行を追加する
                ]
            ],
            'loginAction' => [
                'controller' => 'Users',
                'action' => 'login'
            ],
            'unauthorizedRedirect' => $this->referer(),
            'authError' => __('ログインしてください。')
        ]);
    }

↑のように、authenticate内のfinderキーに対してvalueに'auth'と書いた場合、usersテーブルに対応するUsersTable.phpの中に下記を記載してあげるだけでOK。

src/Model/Table/UsersTable.php

    public function findAuth(\Cake\ORM\Query $query, array $options)
    {
        $query->where(['Users.deleted' => 0]);
        return $query;
    }

こうすると、identify()実行前に↑のwhere条件を追加してからexecuteしてくれるという流れ。findAuthという関数名は前述のfinderキーに設定した'auth'というvalueと連動している。

最後まで読んでいただきありがとうございます!現在、受託的な開発で収入を得るのではなく個人開発でWebサービスを作り、収入のポートフォリオを構築していくために時間を注いでいます!もしサポートしていただけたら大変嬉しいです!