ããã«ã¡ã¯ï¼ä¹ ã ã®ç»å ´ã¨ãªãã¾ã @takoba_ ã§ãï¼ï¼
ãã®ã¨ã³ããªã¯ã ã³ããã Advent Calendar 2021 ã® 8æ¥ç® ã®ã¨ã³ããªã§ãã 7æ¥ç®ã¯ @shnagai ã«ãã ç°ãªããã¼ã¿ã½ã¼ã¹éã®åæããããã¦AWS DMSã«ã¤ãã¦èª¿ã¹ãã®ã§ã¾ã¨ãã¦ã¿ã ã§ããã
CakePHP ã® Authentication ãã©ã°ã¤ã³ã¨ã¯ï¼
CakePHP 㯠CakePHP4 ããªãªã¼ã¹ãããã¿ã¤ãã³ã°ã§ãèªå¯ãããæ©è½ã cakephp/authorization ãã©ã°ã¤ã³ã«ãèªè¨¼ãããæ©è½ã cakephp/authentication ãã©ã°ã¤ã³ã«åé¢ãã¾ãã*1ããããã®ãã©ã°ã¤ã³ã¯ãå®ã¯ PSR-7 ã«æºæ ãã Middleware ãæä¾ãã Composer ããã±ã¼ã¸ã«ãªã£ã¦ããããã¾ããã¤ã¾ãã¯ã PHP çéã«ã¨ã£ã¦ã¯é常ã«ãã¦ãå®è£ ã«ãªãããã§ãï¼
ï¼å ãã¦ã Middleware é¨ãªã©ã«éã£ã¦è¨ãã°ãçè«ä¸ã¯ä»ã®ãã¬ã¼ã ã¯ã¼ã¯ã§ãæµç¨å¯è½ï¼ã¨ããããã§ããããï¼
ï¼ï¼ï¼ãââããããããã°ã¤ã³ç»é¢ã§ã¡ã¼ã«ã¢ãã¬ã¹ã¨ screen_name ã®ã©ã¡ããã ID ã¨ãã¦è¨±å®¹ããããã«ããããããã
ããããããªä¾¿å©ã§ãã¦ãå®è£ ãæã¤ãã©ã°ã¤ã³ã使ãããªãã¦ãããããããªãã§ããããã¨ãã°ãã°ã¤ã³ç»é¢ã§ãã¡ã¼ã«ã¢ãã¬ã¹ã¨ screen_name ã®ã©ã¡ããã ID ã¨ãã¦è¨±å®¹ããããã«ããããããð¢ãã£ã¦ãã¨ãããã¾ãããï¼
ï¼ä¸æ¦ä¸ãåãã¦ã³ã³ãã«å ¥ããã§ã¤ã³ãããã¤ã¤ï¼ããã¾ããããããï¼*2
ãã®å ´åã«ç»å ´ããã®ã cakephp/authentication ãã©ã°ã¤ã³ã«ãªãã¾ãã CakePHP Cookbook ã§ã¯ã CMSãå®è£ ãããã¨ãã±ã¼ã¹ã¹ã¿ãã£ã«ãã¦èªè¨¼æ©è½ã追å ãããã¥ã¼ããªã¢ã« ãç¨æãã¦ããã"ã¡ã¼ã«ã¢ãã¬ã¹ã¨ãã¹ã¯ã¼ã" ã¨ãã£ãåä¸ã®èªè¨¼è¦ç´ ãã¿ã¼ã³ã§ã®èªè¨¼æ©è½ã®å®è£ ã説æãã¦ãã¾ãããå ã»ã©ä¾ç¤ºãã "ã¡ã¼ã«ã¢ãã¬ã¹ã¨ãã¹ã¯ã¼ã" ã¾ã㯠"screen_nameã¨ãã¹ã¯ã¼ã" ã¨ãããããªè¤æ°ã®èªè¨¼è¦ç´ ãã¿ã¼ã³ãå¾ ã¡åããå ´åã«å¯¾ãã¦ãã©ã®ããã«å¯¾å¦ãããã¯èª¬æããã¦ã¾ãã ã§ããã
æ¬ã¨ã³ããªã§ã¯ãä¸è¨ã®ãããªåé¡ã解決ããå®è£ ã説æãããã¨æãã¾ãï¼ðââï¸
åæï¼ ä»åã®ç»å ´äººç©
åçªã ããã¾ã㯠cakephp/authentication ãã©ã°ã¤ã³ã«ç»å ´ããã¯ã©ã¹ãã¡ã®ç´¹ä»ã ï¼ð¸
cf. CakePHP4 ã®èªè¨¼å¦ç cakephp/authentication ã®ã¡ã¢ - Qiita
Authenticator
cf. èªè¨¼æ©è½ - CakePHP Authentication 2.x Cookbook
Authenticatorsã¯ããªã¯ã¨ã¹ããã¼ã¿ãèªè¨¼ã«å¤æããå¦çãè¡ãã¾ãã ãããã¯ã Identifiers ãå©ç¨ãã¦ãæ¢ç¥ã® Identity Objects ãè¦ã¤ãã¾ãã
æ¸ãã¦ããéãã«ããªã¯ã¨ã¹ããã¼ã¿ããèªè¨¼è¦ç´ ãã¿ã¼ã³ã®ãã¼ã¿ãæ½åºãã¾ããå ·ä½çã«ã¯ POSTãã©ã¡ã¼ã¿ ã¨ãã¦å ¥åãããæ å ±ããã¨ã«èªè¨¼è¦ç´ ãã¿ã¼ã³ã ããå«ã¾ãããã¼ã¿ãªãã¸ã§ã¯ãï¼ã¨ãã£ã¦ã Hash ã ãã©ï¼ã«å¤æãããã¨ãã£ãé¨åãæ ããããã§ãã
Identifier
cf. Identifiers - CakePHP Authentication 2.x Cookbook
Identifiersã¯èªè¨¼è ããªã¯ã¨ã¹ãããæ½åºããæ å ±ã«åºã¥ãã¦ã¦ã¼ã¶ããµã¼ãã¹ãèå¥ãã¾ãã Identifiersã¯
loadIdentifierã¡ã½ããã§ãªãã·ã§ã³æå®ãããã¨ãã§ãã¾ãã
èªè¨¼è is ï¼ä¸è¨ã§åºã¦ããï¼Authenticator ã§ãããããã¾ãããã®ä»ã¯æ¸ãã¦ããã¨ãããªãã§ãããå ·ä½çã«ã¯ Authenticator ãæ½åºããèªè¨¼è¦ç´ ãã¿ã¼ã³ããã¨ã«ãã¼ã¿ãã¼ã¹ãªã©ãç §åãã¦ã¦ã¼ã¶ã¼ããµã¼ãã¹ãèå¥ãå°åºãããã¨ãã£ããããã§ãã
AuthenticationService
authentication/AuthenticationService.php at 2.x · cakephp/authentication
èªè¨¼å¦çã«é¢ãã Facade ã®å½¹å²ãæããã¾ããæ¨å¥¨ããã¦ããå®è£
ã§ã¯ãCakePHP ã¢ããªã±ã¼ã·ã§ã³ãæãã class App\Application ã« getAuthenticationService() ãå®ç¾©ããä¸ã§ Component ã Middleware ããå¼ã°ããå®è£
ã«ãªã£ã¦ãã¾ãã
AuthenticationMiddleware
cf. Middleware - CakePHP Authentication 2.x Cookbook
AuthenticationMiddlewareã¯èªè¨¼ãã©ã°ã¤ã³ã®ä¸ã§æå½¢ãã¦ãã¾ãã ããã¯ãã¢ããªã±ã¼ã·ã§ã³ã¸ã®åãªã¯ã¨ã¹ããæãããããããã®èªè¨¼è¨¼æè¨¼ã§ã¦ã¼ã¶ã¼ã®èªè¨¼ã試ã¿ã¾ãã åèªè¨¼æ©è½ã¯ãã¦ã¼ã¶ãèªè¨¼ãããã¾ã§ããããã¯ã¦ã¼ã¶ãè¦ã¤ãããªãã¾ã§é çªã«è©¦è¡ããã¾ãã èªè¨¼ãããå ´åã® ID ã¨èªè¨¼çµæãªãã¸ã§ã¯ããå«ããªã¯ã¨ã¹ãã«ã¯authenticationãidentityãauthenticationResult屿§ãè¨å®ãããèªè¨¼åã«ãã£ã¦æä¾ããã追å ã®ã¨ã©ã¼ãå«ããã¨ãã§ãã¾ãã
AuthenticationService ã使ã£ã¦ãèªè¨¼å¦çãå®è¡ãã¾ãã宿
㯠AuthenticationService::authenticate() ãå®è¡ãã¦ãã¦ãå種 Authenticator ãé ç¹°ãå®è¡ãã¦èªè¨¼ã®è©¦è¡ãè¡ããããã§ãã
$service->loadAuthenticator() ã¯åã Authenticator ãè¤æ°åèªã¿è¾¼ããªãï¼
ãã¦ãæ¬é¡ã«æ»ãã¾ãã
ã¨ãããããåè¿°ããããã°ã¤ã³ç»é¢ã«ããã¦ãã¡ã¼ã«ã¢ãã¬ã¹ã¨ screen_name ã®ã©ã¡ããã ID ã¨ãã¦è¨±å®¹ããããã«ããããã¨ããè¦ä»¶ãæºãããã¨ã以ä¸ã®ãããªå®è£ ãããã¨ãã¾ãã
<?php declare(strict_types=1); namespace App; class Application extends BaseApplication implements AuthenticationServiceProviderInterface { // ããããã¨ç¥ public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $service = new AuthenticationService(); // Load the authenticators. Session should be first. $service->loadAuthenticator('Authentication.Session'); $service->loadAuthenticator('Authentication.Form', [ 'fields' => [ IdentifierInterface::CREDENTIAL_USERNAME => 'email', IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ], ]); $service->loadAuthenticator('Authentication.Form', [ 'fields' => [ IdentifierInterface::CREDENTIAL_USERNAME => 'screen_name', IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ], ]); // 以ä¸ç¥ }
ã¨ããã¨ã以ä¸ã®ãããªã¨ã©ã¼ãåºã¦ãã¾ããã¢ããªã±ã¼ã·ã§ã³ãèµ·åããªããªãã¾ããã
2021-12-0x xx:xx:xx Error: [RuntimeException] The "Form" alias has already been loaded. The `fields` key has a value of `{"username":"screen_name","password":"password"}` but previously had a value of `{"username":"email","password":"password"}` in path/to/app/vendor/cakephp/cakephp/src/Core/ObjectRegistry.php on line 161
ããã¯ã CakePHP ã§ Factory Method ãã¿ã¼ã³ ãå®è£ ããå ´åã«ç¨ãããã ObjectRegistry ã¨ããã¯ã©ã¹ã®ä»æ§ãªãã§ããã ObjectRegistry ã«ç»é²ããã object 㯠key-value ã§ç®¡çããã¦ããã®ã§ã åã key ã® object ã¯å½ç¶è¤æ°æã¦ãªããã¨ãããã¨ã«ãªãã¾ããå°ã£ãï¼
ããããã©ãããï¼
ã§ããããããªã¨ãã«ããã¬ã¼ã ã¯ã¼ã¯ã®ä»æ§ãç¥ã£ã¦ãã¨ãµã¯ãã¨è§£æ±ºã§ããããããã®ã§ããããããã¯ä¸è¨åé¡ã®è§£æ±ºæ¹æ³ã説æãã¦ããã¾ãã
1. Authenticator 群ã®è¨å®
ã¾ã㯠Authenticator 群ãã©ã®ããã«è¨å®ãããèãã¾ããããã§ã¯2ã¤ã®ãã¿ã¼ã³ããã£ãã®ã§ãåæ¹èª¬æãã¦ããã¾ãã
1-1. FormAuthenticator ã load ããéã« alias ãã¤ãã¦åé¿ãã
ã¾ãã ObjectRegistry ã¯åºæ¬çã« key ã®æååãã Cake\Core\App::className() ãç¨ãã¦ã¯ã©ã¹åãå°åºããæçãæ¡ãã¾ããã§ãããObjectRegistry ã§ load ããéã« className ã¨ãã option ãè¨å®ããã¨ãkeyã¯èªç±ãªæååãè¨å®ãããã¨ãã§ããããã«ãªãã¾ãã
ä¸è¨ãå©ç¨ãã¦ãå®è£ ããã®ã以ä¸ã®ã³ã¼ãã§ãã
<?php declare(strict_types=1); namespace App; use Authentication\Authenticator\FormAuthenticator; class Application extends BaseApplication implements AuthenticationServiceProviderInterface { // ããããã¨ç¥ public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $service = new AuthenticationService(); // Load the authenticators. Session should be first. $service->loadAuthenticator('Authentication.Session'); $service->loadAuthenticator('Authentication.FormWithEmail', [ 'fields' => [ IdentifierInterface::CREDENTIAL_USERNAME => 'email', IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ], 'className' => FormAuthenticator::class, ]); $service->loadAuthenticator('Authentication.FormWithScreenName', [ 'fields' => [ IdentifierInterface::CREDENTIAL_USERNAME => 'screen_name', IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ], 'className' => FormAuthenticator::class, ]); // 以ä¸ç¥ }
1-2. src/Authenticator/ ã«ã«ã¹ã¿ã ãã Authenticator ãå®è£ ãã
ããã²ã¨ã¤ã®æ¹æ³ã¨ãã¦ã¯ãclass Authentication\Authenticator\AbstractAuthenticator ãç¶æ¿ããã«ã¹ã¿ã Authenticator ãå®ç¾©ãã¦ããããå©ç¨ããæ¹æ³ãããã¾ãã
ä»åã®å ´åã¯ãã¾ã class Authentication\Authenticator\FormAuthenticator ãç¶æ¿ãã class App\Authenticator\FormWithEmailAuthenticator ã以ä¸ã®ããã«å®ç¾©ãã¾ãã
<?php declare(strict_types=1); namespace App\Authenticator; use Authentication\Authenticator\FormAuthenticator; use Authentication\Identifier\IdentifierInterface; /** * Form Authenticator with email */ class FormWithEmailAuthenticator extends FormAuthenticator { /** * @inheritDoc */ public function __construct(IdentifierInterface $identifier, array $config = []) { parent::__construct($identifier, $config); $this->setConfig('fields', [ IdentifierInterface::CREDENTIAL_USERNAME => 'email', IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ]); } }
ä¸è¨ã«å£ã£ã¦ã class App\Authenticator\FormWithScreenNameAuthenticator ãå®ç¾©ãã¦ããã¾ãã
ãã®ãã¨ã«ã Application::getAuthenticationService() ã§ã以ä¸ã®ããã«è¨å®ãã¾ãã
<?php declare(strict_types=1); namespace App; class Application extends BaseApplication implements AuthenticationServiceProviderInterface { // ããããã¨ç¥ public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $service = new AuthenticationService(); // Load the authenticators. Session should be first. $service->loadAuthenticator('Authentication.Session'); $service->loadAuthenticator('FormWithEmail'); $service->loadAuthenticator('FormWithScreenName'); // 以ä¸ç¥ }
ã©ãã§ãï¼ãã£ã¡ã®æ¹ãã·ã¥ãã¨ãã¦ãããããããã¾ããã
2. PasswordIdentifier ã¯å²ã¨æè»ãªã®ã§ãã¡ãã£ã¨configãå¤ããã°ããã¡ãã
1.ã§ Authenticator ã®è¨å®ã¯å®äºãã¾ããããç¶ãã¦ã¯ Identifier ã®è¨å®ã夿´ããå¿ è¦ãããã¾ãã
ãã¹ã¯ã¼ãèªè¨¼ã«ç¨ãã class Authentication\Identifier\PasswordIdentifier ã¯å²ã¨æè»ã«èªè¨¼è¦ç´ ã®æ¡å¼µãã§ããã®ã§ã以ä¸ã®ããã« ['email', 'screen_name'] ã¨ã㦠email ã screen_name ã許容ããããã«è¨å®ãã¦ããã¾ãã
<?php declare(strict_types=1); namespace App; class Application extends BaseApplication implements AuthenticationServiceProviderInterface { // ããããã¨ç¥ public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $service = new AuthenticationService(); // Load the authenticators. Session should be first. $service->loadAuthenticator('Authentication.Session'); $service->loadAuthenticator('FormWithEmail'); $service->loadAuthenticator('FormWithScreenName'); // Load identifiers $service->loadIdentifier('Authentication.Password', [ 'fields' => [ IdentifierInterface::CREDENTIAL_USERNAME => ['email', 'screen_name'], IdentifierInterface::CREDENTIAL_PASSWORD => 'password', ], ]); return $service; }
ããã§ãæ±ãããã¦ããããã°ã¤ã³ç»é¢ã«ããã¦ãã¡ã¼ã«ã¢ãã¬ã¹ã¨ screen_name ã®ã©ã¡ããã ID ã¨ãã¦è¨±å®¹ããããã«ããããã¨ããè¦ä»¶ãéæã§ãã¾ããï¼å©ãã£ããââãããï¼ð±
ãããã«
ã©ãã§ããï¼ãã¬ã¼ã ã¯ã¼ã¯ããã©ã°ã¤ã³ã®ä»æ§ãç¥ã£ã¦ãã¨ãã¡ãã£ã¨è¨å®ãå¤ããã ãã§ãããªã«æè»ã«å¯¾å¿ã§ããããã«ãªãã¾ããï¼ã¨ã¦ããããããð
ã¿ããªã CakePHP ã cakephp/authentication ãã©ã°ã¤ã³ã¨ä»²è¯ããªã£ã¦ãããã¼ã©ã¤ããéããã¦ãã ããï¼ð
ã³ããã社ã§ã¯ãã¼ããã¨ä¸ç·ã« CakePHP ã«è©³ãããªããªããããªããªéçºãæ¨é²ãã¦ãã£ã¦ãããã¨ã³ã¸ãã¢ãã¡ã大åéãã¦ããã¾ãï¼ä»¥ä¸ãããã²å¿åãã¦ããããªããð¤
- PHPã¨AWSã§ã¦ã¼ã¶ã¼ãæ¯ãããµã¼ãã¹ãã¤ããããã¯ã¨ã³ãã¨ã³ã¸ãã¢åéï¼ | ã³ãããæ ªå¼ä¼ç¤¾
- å®¶æåããµã¼ãã¹éå¶ããã¯ã«ã³ããã¼ãããã«ãã¼ã¿ããªãã³ãªçµç¹ã¸ã¨å°ãã¦ãããããµã¼ãã¼ãµã¤ãã¨ã³ã¸ãã¢åéï¼ | ã³ãããæ ªå¼ä¼ç¤¾
ææ¥ã¯ @otukutun ã«ããã¨ã³ããªã§ãï¼ããã®ãã¿ã«ããð
åè
- Quick Start - CakePHP Authentication 2.x Cookbook
- Quick Start - CakePHP Authorization 2.x Cookbook
- èªè¨¼æ©è½ - CakePHP Authentication 2.x Cookbook
- Identifiers - CakePHP Authentication 2.x Cookbook
- èªè¨¼ã¨èªå¯ã®éããã¾ã¨ãã¦ã¿ã - zenn.dev
- CakePHP4 ã®èªè¨¼å¦ç cakephp/authentication ã®ã¡ã¢ - Qiita
- ObjectRegistryã«ã¤ãã¦
*1:æ§æ¥å©ç¨ããã¦ãã AuthComponent ã¯ã CakePHP 4.0.0 ããªãªã¼ã¹ãããã¿ã¤ãã³ã°ã§éæ¨å¥¨ã¨ãªãã¾ãã
*2:æªå¥!Yesã©ãããRPGã®æ¼«æã財å¸ãæ¾ã£ãããã