CakePHP2 から CakePHP4 への移行について (3)


前回前々回は CakePHP2 から CakePHP4 の移行作業として、CakePHP2 側のソースのリファクタリングと、CakePHP4 の仕様に合わせてソースの一括変換を行うコンバータの考え方について書きました。今回は認証機能の移行について書きたいと思います。

認証機能の追加

CakePHP4 の認証には、CakePHP2 と同様に AuthComponent を使用する方法と、Authentication プラグインを使用する方法の2つの方法があります。これまでと同様、AuthComponent を使用したいところですが、CakePHP4 では非推奨となっており、今後 Authentication プラグインに置き換えられる予定となっています。そこで今後も長く使用できるように Authentication プラグインを使用することといたしました。

具体的には以下のような手順で認証機能を追加します。

1. composer を使って Authentication プラグインをインストールします。
(事前に composer のインストールが必要です。コマンドプロンプトでルートディレクトリに移動し、以下のコマンドを実行します。)

composer require "cakephp/authentication:^2.0"

2. src\Application.php に以下のクラスを追加します。

use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Identifier\IdentifierInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ServerRequestInterface;

3. src\Application.php のクラスの宣言を以下のとおり変更します。

// 変更前
class Application extends BaseApplication

// 変更後
class Application extends BaseApplication implements AuthenticationServiceProviderInterface

4. src\Application.php に以下のメソッドを追加します。

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        ->add(new RoutingMiddleware($this))
        ->add(new AuthenticationMiddleware($this));

    return $middlewareQueue;
}

public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    $service = new AuthenticationService();
    $authenticationService = new AuthenticationService([
        'unauthenticatedRedirect' => '/users/login',
        'queryParam' => 'redirect',
    ]);

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

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

    $authenticationService->loadAuthenticator('Authentication.Form', [
        'fields' => $fields,
        'loginUrl' => '/users/login',
    ]);

    return $authenticationService;
}

5. src\Controller\AppController.php の initialize メソッドに以下のコードを追加します。

$this->loadComponent('Authentication.Authentication');

6. 無限リダイレクトループを防止するために、src\Controller\UsersController.php と src\Controller\Admin\UsersController.php beforeFilter のメソッドに以下のコードを追加します。

$this->Authentication->addUnauthenticatedActions(['login']);

7. src\Controller\UsersController.php と src\Controller\Admin\UsersController.に以下のメソッドを追加(変更)します。

public function login()
{
    $this->request->allowMethod(['get', 'post']);
    $result = $this->Authentication->getResult();
    
    // 認証がOKの場合
    if($result->isValid())
    {
        // ログイン後の画面に遷移
        return $this->redirect(['controller' => 'Users', 'action' => 'index']);
    }

    // ユーザーが submit 後、認証失敗した場合は、エラーを表示します
    if($this->request->is('post') && !$result->isValid())
    {
        $this->Flash->error(__('ログインID、もしくはパスワードが正しくありません'));
    }
}

より詳しい情報は以下のURLにて確認可能です。
CakePHP Authentication 2.x Cookbook
https://book.cakephp.org/authentication/2/ja/index.html

CakePHP2 で保存されたパスワードの引き継ぎ

CakePHP4 ではパスワードのハッシュ化のアルゴリズムに bcrypt が採用されています。CakePHP4 で新規にシステムを構築する場合はこの方法で問題ないのですが、CakePHP2 からの移行の場合、既存のユーザのパスワードのハッシュを引き継ぐ必要があります。CakePHP2 ではハッシュ関数に SHA-1 が使用されており、スムーズな移行が可能なようにCakePHP4 でも SHA-1 をサポートすることにしました。

具体的には以下の手順で SHA-1 のハッシュの設定を行います。

  1. config\app_local.php にCakePHP2側の app\Config\core.php で指定していた Security.salt を以下のように指定します。
'Security' => [
    'salt' => env('SECURITY_SALT', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'),
],

2. 指定した Security.salt を使用するため config\bootstrap.php に以下のコードを追加します。

Security::setSalt(Configure::read('Security.salt'));

3. src/Application.php の getAuthenticationService メソッドに以下のコードを追加します。

$service->loadIdentifier('Authentication.Password', [
    'passwordHasher' => [
        'className' => 'Authentication.Fallback',
        'hashers' => [
            'Authentication.Default',
            [
                'className' => 'Authentication.Legacy',
                'hashType' => 'sha1',
                'salt' => true
            ],
        ]
    ]
]);

これで CakePHP2 で保存したパスワードを使用して、CakePHP4 でもログインができるようになります。

bcrypt でハッシュ化されたパスワードについて

CakePHP2 で使用していたパスワードを引き継ぎ、CakePHP4 でも同じパスワードでログインできるようになりましたが、CakePHP4 でパスワードを変更した場合は、bcrypt にて以下のような形式でハッシュ化され、データベースに保存されます。

$2y$10$AbCd1EfGH2IjkL3MN4fGH2IjkL3jkL3MN4fGH2IjkL3MN4fGH2Ijk

これは次のような意味があります。

1-3桁目 $2y ハッシュアルゴリズム(2, 2a, 2b, 2x, 2y 等の種類があります。)
4-6桁目 $10 ストレッチング回数(2のストレッチング回数分、連続してハッシュ化を行います。10の場合、2の10乗=1024回ハッシュ値への計算を行います。)
7-29桁目 AbCd1EfGH2IjkL3MN4fGH2I ソルト(パスワードに付加する文字列。CakePHP2 では設定ファイルに記述していましたが、bcrypt ではレコードごとに変化します。)
30-59桁目 jkL3jkL3MN4fGH2IjkL3MN4fGH2Ijk ハッシュ値(ストレッチング回数分計算した結果のハッシュ値。入力されたパスワードのハッシュ値と、保存されているハッシュ値が一致していれば認証がOKとなります。)

CakePHP2 は全てのパスワードでソルトが固定となっていましたが、CakePHP4 ではレコードごとに異なり、CakePHP2 に比べてパスワードの安全性が向上しています。

関連記事:

One thought on “CakePHP2 から CakePHP4 への移行について (3)”

  1. 非常に参考になります。
    実際行われてみた時の、他のノウハウなども期待しています。

kaihei777 へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


This site uses Akismet to reduce spam. Learn how your comment data is processed.