※環境: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チェックを行いません。