会員ページと管理者ページの認証を分ける実装を、Authenticationプラグインを使って行ってみました。
・会員ページは、Membersテーブルを参照し、emailとpasswordでログイン
・管理者ページは、Usersテーブルを参照し、usernameとpasswordでログイン
##1.teble作成
##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フォルダを作成.
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 を追加
インポート:
use App\Authentication\AppAuthenticationServiceProvider;
use Authentication\Middleware\AuthenticationMiddleware;
AuthenticationMiddleware を追加:
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
...
->add(new AuthenticationMiddleware(
new AppAuthenticationServiceProvider()
));
return $middlewareQueue;
}
###2-4.AppControllerにて、Componentをロード
public function initialize(): void
{
....
$this->loadComponent('Authentication.Authentication');
}
public function beforeFilter(EventInterface $event)
{
$this->Authentication->allowUnauthenticated(['login']);
}
##3.ログインアクションの構成
###3-1.login/logoutを実装
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']);
}
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.ログインページの作成
メンバーページは、メールアドレスとパスワードでフォームを作成
<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>
管理者ページは、ユーザネームとパスワードでフォームを作成
<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にて認証処理を分けます。
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;
}
}