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. 非常に参考になります。
    実際行われてみた時の、他のノウハウなども期待しています。

コメントを残す

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

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください