5
6

More than 3 years have passed since last update.

CakePHPで2種類(会員/管理者)の認証を実装 [ Authentication ]

Last updated at Posted at 2021-02-09

会員ページと管理者ページの認証を分ける実装を、Authenticationプラグインを使って行ってみました。

・会員ページは、Membersテーブルを参照し、emailとpasswordでログイン
・管理者ページは、Usersテーブルを参照し、usernameとpasswordでログイン

1.teble作成

Membersテーブル
スクリーンショット 2021-02-09 11.23.02.png

Usersテーブル
スクリーンショット 2021-02-09 11.23.31.png

2.Authenticationプラグイン 導入

参考:
CakePHP Authentication 2.x Cookbook
https://book.cakephp.org/authentication/2/ja/index.html
CakePHP 4 で Authentication を Application.php の肥大化を防ぎつつ導入する方法
https://tt-computing.com/cake4-app-authc-svc-provider

2-1.インストール

php composer.phar require "cakephp/authentication:^2.0"

2-2.独自のクラス AppAuthenticationServiceProviderの実装

srcにAuthenticationフォルダを作成.

app/src/Authentication/AppAuthenticationServiceProvider.php
declare(strict_types=1);

namespace App\Authentication;

use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Identifier\IdentifierInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\Router;
use Psr\Http\Message\ServerRequestInterface;

class AppAuthenticationServiceProvider implements AuthenticationServiceProviderInterface
{
    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        $service = new AuthenticationService();

        // 認証されていない場合にユーザーがどこにリダイレクトするかを定義します。
        $service->setConfig([
           'unauthenticatedRedirect' => '/users/login',
           'queryParam' => 'redirect',
         ]);

        $fields = [
           IdentifierInterface::CREDENTIAL_USERNAME => 'email',
           IdentifierInterface::CREDENTIAL_PASSWORD => 'password'
        ];

        // 認証者を読み込みます。セッションを優先してください。
        $service->loadAuthenticator('Authentication.Session');
        $service->loadAuthenticator('Authentication.Form', [
           'fields' => $fields,
           'loginUrl' => '/users/login'
        ]);

        // 識別子を読み込みます。
        $service->loadIdentifier('Authentication.Password', compact('fields'));

        return $service;
    }
}

2-3.src/Application.phpにAuthenticationMiddleware を追加

インポート:

src/Application.php
use App\Authentication\AppAuthenticationServiceProvider;
use Authentication\Middleware\AuthenticationMiddleware;

AuthenticationMiddleware を追加:

src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
    {
        $middlewareQueue
        ...
        ->add(new AuthenticationMiddleware(
                new AppAuthenticationServiceProvider()
            ));

        return $middlewareQueue;
    }

2-4.AppControllerにて、Componentをロード

src/Controller/AppController.php
public function initialize(): void
{
....
 $this->loadComponent('Authentication.Authentication');
}

public function beforeFilter(EventInterface $event)
{
   $this->Authentication->allowUnauthenticated(['login']);        
}

3.ログインアクションの構成

3-1.login/logoutを実装

MembersController.php
    public function login(){

        $result = $this->Authentication->getResult();
        if ($result->isValid()) {
            $target = $this->Authentication->getLoginRedirect() ?? '/members';
            return $this->redirect($target);
        }
        if ($this->request->is('post') && !$result->isValid()) {
             $this->Flash->error(__('メールアドレスとパスワードが無効です'));
        }

    }

    public function logout()
    {
        $this->Authentication->logout();
        return $this->redirect(['controller' => 'Members', 'action' => 'login']);
    }

UsersController.php
    public function login(){

        $result = $this->Authentication->getResult();
        if ($result->isValid()) {
            $target = $this->Authentication->getLoginRedirect() ?? '/users';
            return $this->redirect($target);
        }
        if ($this->request->is('post') && !$result->isValid()) {
             $this->Flash->error(__('ユーザー名とパスワードが無効です'));
        }

    }

    public function logout()
    {
        $this->Authentication->logout();
        return $this->redirect(['controller' => 'users', 'action' => 'login']);
    }

ログインするために、パスワードのハッシュ化。
Model/Entity/Users.php
Model/Entity/Members.php

use Cake\Auth\DefaultPasswordHasher;
protected function _setPassword($password)
{
   if (strlen($password) > 0) {
      return (new DefaultPasswordHasher)->hash($password);
   }
}

3-2.ログインページの作成

メンバーページは、メールアドレスとパスワードでフォームを作成

Template/Members/login.php
<form method="post">
    <fieldset>
        <label>Email</label>
        <input type="text" name="email">
        <label>Password</label>
        <input type="password" name="password">
        <input
            type="hidden" name="_csrfToken" autocomplete="off"
            value="<?= $this->request->getAttribute('csrfToken') ?>">
        <button class="button-primary" type="submit">ログイン</button>
    </fieldset>
</form>

管理者ページは、ユーザネームとパスワードでフォームを作成

Template/Users/login.php
<form method="post">
    <fieldset>
        <label>Email</label>
        <input type="text" name="username">
        <label>Password</label>
        <input type="password" name="password">
        <input
            type="hidden" name="_csrfToken" autocomplete="off"
            value="<?= $this->request->getAttribute('csrfToken') ?>">
        <button class="button-primary" type="submit">ログイン</button>
    </fieldset>
</form>

4.認証の分岐

2-2.で実装した、AppAuthenticationServiceProviderにて認証処理を分けます。

app/src/Authentication/AppAuthenticationServiceProvider.php

class AppAuthenticationServiceProvider implements AuthenticationServiceProviderInterface
{
    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        //ServerRequestInterfaceでリクエストされたコントローラーを取得します.
        $controller = $request->getParam('controller');

        $service = new AuthenticationService();

        //リクエストコントローラで分岐.
        if($controller === 'Members'){
            $service = $this->set_member($service);
        }

        if($controller === 'Users'){
            $service = $this->set_users($service);
        }
        return $service;
    }

    private function set_member($service){

        $service->setConfig([
            'unauthenticatedRedirect' => Router::url([
                'prefix' => false,
                'plugin' => null,
                'controller' => 'Members',
                'action' => 'login']),
            'queryParam' => 'redirect',
        ]);


        $fields = [
            IdentifierInterface::CREDENTIAL_USERNAME => 'email',
            IdentifierInterface::CREDENTIAL_PASSWORD => 'password'
        ];

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

        $service->loadAuthenticator('Authentication.Form',[
                'fields' => $fields,
                'loginUrl' => Router::url([
                    'prefix' => false,
                    'plugin' => null,
                    'controller' => 'Members',
                     'action' => 'login'
                ]),
        ]);


        $service->loadIdentifier('Authentication.Password',[
            'resolver'=>[                               
                'className' => 'Authentication.Orm',    
                'userModel' => 'Members' //ここで Members を指定
            ],               
            //認証に使用するフィールド          
            'fields' => [
                'username' => 'email',
                'password' => 'password',
            ]
        ]);


        return $service;
    }

    private function set_users($service){


        $service->setConfig([
            'unauthenticatedRedirect' => Router::url([
                'prefix' => false,
                'plugin' => null,
                'controller' => 'Users',
                'action' => 'login']),
                'queryParam' => 'redirect',
        ]);


        $fields = [
            IdentifierInterface::CREDENTIAL_USERNAME => 'username',
            IdentifierInterface::CREDENTIAL_PASSWORD => 'password'
        ];

        /*
        ユーザーデータのセッションキー、 デフォルトは Auth.
        AuthはMemberでのログインで使用している為、セッションキーを変更する
        */
        $service->loadAuthenticator('Authentication.Session',[
            'sessionKey' => 'AdminAuth',
        ]);

        $service->loadAuthenticator('Authentication.Form',[
                'fields' => $fields,
                'loginUrl' => Router::url([
                    'prefix' => false,
                    'plugin' => null,
                    'controller' => 'Users',
                     'action' => 'login'
                ]),
        ]);

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


        return $service;
    }
}
5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6