【CakePHP】CakePHP4でAjaxからのPOSTが403(Forbidden)エラーになる現象の解決策

※環境:CakePHP 4.0.3

※現象:jQueryのajaxでPOSTを投げるとき、403(Forbidden)が返されました。

※原因:
「config/routes.php」に全体のCSRFチェックの処理がデフォルトで入っているため、フォーム以外からのPOSTはエラーになります。

※対策:
・「config/routes.php」の全体のCSRFチェックをコメントアウトします。
・「src/Application.php」で個別にホワイトリスト(CSRFのチェックを行わないコントローラとアクション)を設定します。

↓↓(例)

(1)「config/routes.php」の修正:4行コメントアウト

$routes->scope('/', function (RouteBuilder $builder) {

//    $builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([ // ← この行をコメントアウト
//        'httpOnly' => true,                                             // ← この行をコメントアウト
//    ]));                                                                // ← この行をコメントアウト

//    $builder->applyMiddleware('csrf');                                  // ← この行をコメントアウト

    // ・・・以下省略・・・

});

(2)「src/Application.php」の修正:3ヶ所追加

use Cake\Http\Middleware\CsrfProtectionMiddleware;  // 名前空間の記述を追加


    // ・・・中略・・・
    
    
    public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
    {
                // ↓↓ここから追加
        $csrf = new CsrfProtectionMiddleware(['httpOnly' => true]);
        $csrf->whitelistCallback(function ($request) {
            $controller = $request->getParam('controller');
            $action = $request->getParam('action');
            if (is_null($controller) || is_null($action)) {
                return false;
            }
            // ↓↓ホワイトリストの指定
            $aryOkControllersAndActions = [
                ['controller' => 'Articles', 'action' => 'add'],
                ['controller' => 'Articles', 'action' => 'edit'],
                ['controller' => 'Articles', 'action' => 'delete'],
                ['controller' => 'Users', 'action' => 'add'],
            ];
            // ↑↑ホワイトリストの指定
            foreach($aryOkControllersAndActions as $aryOkControllerAndAction) {
                if (strcmp($controller, $aryOkControllerAndAction['controller']) == 0 && strcmp($action, $aryOkControllerAndAction['action']) == 0) {
                    return true;
                }
            }
            return false;
        });
        // ↑↑ここまで追加
        
        
        $middlewareQueue
            // Catch any exceptions in the lower layers,
            // and make an error page/response
            ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
            
            // Handle plugin/theme assets like CakePHP normally does.
            ->add(new AssetMiddleware([
                'cacheTime' => Configure::read('Asset.cacheTime'),
            ]))
            
            // Add routing middleware.
            // If you have a large number of routes connected, turning on routes
            // caching in production could improve performance. For that when
            // creating the middleware instance specify the cache config name by
            // using it's second constructor argument:
            // `new RoutingMiddleware($this, '_cake_routes_')`
            ->add(new RoutingMiddleware($this))
            ->add($csrf); // ← ここに「->add($csrf)」を追加(セミコロン「;」の記述に要注意)
            
        return $middlewareQueue;
    }

↑上記の例では、「Articles/add」「Articles/edit」「Articles/delete」「Users/add」に対してだけ、CSRFチェックを行いません。

コメントを残す

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