CakePHP4で複数のテーブル情報を使って認証(ログイン)を実装する方法

CakePHP4で複数のテーブル情報を使って認証(ログイン)を実装する方法

232 回閲覧されました

みなさんこんにちは、jonioです。

今回はCakePHP4で複数のテーブルの情報を使ってログインをする方法を解説します。

CakePHPのバージョン

4.5.4です。

今回使うテーブル

usersテーブルとcompaniesテーブルです。

usersテーブルの情報を使ってログインができますがcompaniesテーブルの情報を使ってもログインできるようにします。

Application.php

usersテーブル・companiesテーブルのどちらを使ってもログインが可能にします。

「CakePHPのプロジェクト > src > Application.php」に下記の記述をします。

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
  $authService = new AuthenticationService();

  $url = $request->getPath();

  //companiesテーブルでログイン
  if (str_contains($url, '/companies')) {
    $authService->loadIdentifier('Authentication.Password', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'resolver' => ['className' => 'Authentication.Orm', 'userModel' => 'Companies'],
    ]);

    $authService->loadAuthenticator('Authentication.Session');

    $authService->loadAuthenticator('Authentication.Form', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'loginUrl' => Router::url('/companies/login'),
    ]);
  } else {
  // usersテーブルでログイン
    $authService->loadIdentifier('Authentication.Password', [
      'fields' => ['username' => 'email', 'password' => 'password'],
    ]);

    $authService->loadAuthenticator('Authentication.Session');
            
    $authService->loadAuthenticator('Authentication.Form', [
      'fields' => ['username' => 'email', 'password' => 'password'],
      'loginUrl' => Router::url('/users/login'),
    ]);
  }

  return $authService;
}

9行目〜12行目でcompaniesテーブルの情報を使ってログインできるようにします。

14行目はログインが成功した時にセッション情報を保存してセッションが切れるまでログインしなくてもよくします。

16行目〜19行目はフォームに入力した内容でログイン認証ができるようにする為の設定で18行目はcompaniesテーブルでログインする時のURLです。

このコードの書き方をすれば3つ以上の認証も可能です。

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
  $authService = new AuthenticationService();

  $url = $request->getPath();

  //companiesテーブルでログイン
  if (str_contains($url, '/companies')) {
    $authService->loadIdentifier('Authentication.Password', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'resolver' => ['className' => 'Authentication.Orm', 'userModel' => 'Companies'],
    ]);

    $authService->loadAuthenticator('Authentication.Session');

    $authService->loadAuthenticator('Authentication.Form', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'loginUrl' => Router::url('/companies/login'),
    ]);
  } else if($url, '/shops') {
    $authService->loadIdentifier('Authentication.Password', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'resolver' => ['className' => 'Authentication.Orm', 'userModel' => 'Shops'],
    ]);

    $authService->loadAuthenticator('Authentication.Session');

    $authService->loadAuthenticator('Authentication.Form', [
      'fields' => ['username' => 'mail', 'password' => 'password'],
      'loginUrl' => Router::url('/companies/login'),
    ]);
  } else {
    // usersテーブルでログイン
      $authService->loadIdentifier('Authentication.Password', [
        'fields' => ['username' => 'email', 'password' => 'password'],
      ]);

      $authService->loadAuthenticator('Authentication.Session');
            
      $authService->loadAuthenticator('Authentication.Form', [
        'fields' => ['username' => 'email', 'password' => 'password'],
        'loginUrl' => Router::url('/users/login'),
      ]);
  }

  return $authService;
}

20行目〜32行目を追加しています。

CompaniesTable.php

パスワードのハッシュ化をします。

「CakePHPのプロジェクト > src > Model > Table > CompaniesTable.php」に下記の記述をします。

<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;


//ここから追加
use Cake\Event\EventInterface;
use Cake\Auth\DefaultPasswordHasher;
use ArrayObject;
//ここまで追加



class CompaniesTable extends Table
{




                  
  
  //ここから追加                
  public function beforeSave(EventInterface $event, $entity, ArrayObject $options)
  {
    if ($entity->isNew() || $entity->isDirty('password')) { 
      if (isset($entity->password) && !empty($entity->password)) {
        $entity->password = (new DefaultPasswordHasher())->hash($entity->password);
      }
    }
  }  
  //ここまで追加
  
                  
}

パスワードはハッシュ化しないとログインできない仕様みたいです。

Companiesコントローラー

下記の記述をします。

public function login()
{
  $this->request->allowMethod(['get', 'post']);
  $result = $this->Authentication->getResult();

  if ($result->isValid()) {
    return $this->redirect('/');
  }

  if ($this->request->is('post') && !$result->isValid()) {
    $this->Flash->error(__('Invalid name or mail'));
  }
}

public function logout()
{
  $this->Authentication->logout();
  
  return $this->redirect('/companies/login');
}

login.php

下記の記述をします。

<?= $this->Form->create() ?>
<?= $this->Form->control('mail', ['label' => 'Email']) ?>
<?= $this->Form->control('password', ['label' => 'Password']) ?>
<?= $this->Form->button('Login') ?>
<?= $this->Form->end() ?>

これで複数認証の完成です。

注意点

usersテーブルのパスワードをcompaniesテーブルのパスワードとしても使うとエラーになってログインできないです。

仕様と思われます。