Laravel

【Laravel】CORSの許可設定を行う

WebAPIを「Laravel」で開発して、フロントエンドで「axios」等を使用して通信した場合に以下のエラーメッセージが表示されるケースがあります。

Access to XMLHttpRequest at 'http://localhost:9080/data' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

上記のエラーはバックエンドの「Laravel」は「Docker」でサーバーを立てて、フロントエンドは「yarn run dev」などのローカルサーバーを立てて開発した場合に発生するエラーとなります。
API通信する場合、通信元が「プロトコル」「ホスト」「ポート」のそれぞれが一致しないとエラーとなるため「CROS」対策が必要となります。
今回はバックエンド側の「Laravel」で通信元が関係なく通信を受け取るようにする必要があります。

「Laravel」で「CORS」対策を行う

最新の「Laravel」であれば、CORS対策のミドルウェアが既に入ってるはずです。
確認する方法は「app/Http/Kernel.php」の中に「$middleware」の項目に「HandleCors」の記述が定義されているか確認します。

protected $middleware = [
        ...省略
        \Illuminate\Http\Middleware\HandleCors::class,  // ここがCORS対策
        ...省略
    ];

Laravelでは「config/cors.php」のファイルがあるはずです。
古いLaravelでは入っていないので、無い場合は作成します。
設定内容は以下の通りです。

<?php
return [
    'paths' => ['*'],

    // 許可されるHTTPメソッド
    'allowed_methods' => ['*'],

    // 許可されるホスト
    'allowed_origins' => ['*'],

    // 許可されるホスト(正規表現による設定)
    'allowed_origins_patterns' => [],

    // 許可されるヘッダー設定
    'allowed_headers' => ['*'],

    // カスタムヘッダーを公開する
    'exposed_headers' => [],

    // CORSレスポンスのキャッシュ
    'max_age' => 0,

    // CORSによるHTTPセッション
    'supports_credentials' => false,
];

上記は全てのアクセス元に対して受け取るようにしておりますので、制限をかけたい場合などは各所設定するようにします。
設定後に「axos」でアクセスして通信が出来れば設定が完了します。

「Lumen」で「CORS」対策(Lumen10以降)

「Lumen」の9以前までは「laravel-cors」を使用して「CORS」対策を行っていましたが、
Lumen10以降でインストールしようとするとエラーが出るため、以下の方法で対応します。
※Lumen9以前の対応は下記に記載しております。

「Middleware」の作成

app/Http/Middleware」に「CorsMiddleware.php」を作成して以下のコードを記述します。

<?php

namespace app\Http\Middleware;
use Closure;

class CorsMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next): mixed
    {
        // 「config/cors.php」の設定を取得する
        $headers = [
            'Access-Control-Allow-Origin'      => config('cors.allowed_origins', '*'),
            'Access-Control-Allow-Methods'     => config('cors.allowed_methods', 'GET, POST, PUT, DELETE, OPTIONS'),
            'Access-Control-Allow-Credentials' => 'true',
            'Access-Control-Max-Age'           => config('cors.max_age', '86400'),
            'Access-Control-Allow-Headers'     => config('cors.allowed_headers', 'Content-Type, Authorization, X-Requested-With')
        ];

        if ($request->isMethod('OPTIONS'))
        {
            return response()->json('{"method":"OPTIONS"}', 200, $headers);
        }

        $response = $next($request);
        foreach($headers as $key => $value)
        {
            $response->header($key, $value);
        }

        return $response;
    }
}

上記の設定を「config/cors.php」に記載していきます。

<?php
return [
    // 許可されるHTTPメソッド
    'allowed_methods' => env('CORS_ALLOWED_METHODS', 'GET, POST, PUT, DELETE, OPTIONS'),

    // 許可されるホスト
    'allowed_origins' => env("CORS_ALLOWED_ORIGINS" , "*"),

    // 許可されるヘッダー設定
    'allowed_headers' => env("CORS_ALLOWED_HEADERS", "Content-Type, Authorization, X-Requested-With"),

    // CORSレスポンスのキャッシュ
    'max_age' => env("CORS_MAX_AGE", "86400"),
];

環境に応じて「.env」ファイルに設定してください。

またミドルウェアを使用出来るようにするために「bootstrap/app.php」に以下のコードを追加します。

// ミドルウェアを使用する
$app->middleware([
    app\Http\Middleware\CorsMiddleware::class
]);

// config/cors.phpを読み込めるようにする
$app->configure('cors');

「Lumen」で「CORS」対策(Lumen9以前まで)

※以下の方法は「lumen9」までの動作となります。
「lumen10」以降は別の方法があります。

laravel-corsのインストール

Lumen」では標準に「CORS」対策のミドルウェアが入っていないので追加する必要があります。
以下のコマンドでパッケージをインストールします。

composer require fruitcake/laravel-cors

「app.php」に記述

bootstrap/app.php」に「ServiceProvider」を登録する箇所に以下のコードを追加します。
また同様に「Middleware」の登録に追加します。

/*
|--------------------------------------------------------------------------
| Register Middleware
|--------------------------------------------------------------------------
|
| Next, we will register the middleware with the application. These can
| be global middleware that run before and after each request into a
| route or middleware that'll be assigned to some specific routes.
|
*/
$app->middleware([
    Fruitcake\Cors\HandleCors::class  // CORS対策を追加
]);

...省略

/*
|--------------------------------------------------------------------------
| Register Service Providers
|--------------------------------------------------------------------------
|
| Here we will register all of the application's service providers which
| are used to bind services into the container. Service providers are
| totally optional, so you are not required to uncomment this line.
|
*/
...省略
$app->register(Fruitcake\Cors\CorsServiceProvider::class);  // CORS対策

「config/cors.php」の作成

プロジェクト直下に「config」フォルダを作成して「cors.php」を追加して以下の設定を定義します。

<?php
return [
    // 許可するパスの制限
    'paths' => ['apis/*'],

    // 許可されるHTTPメソッド
    'allowed_methods' => ['*'],

    // 許可されるホスト
    'allowed_origins' => ['*'],

    // 許可されるホスト(正規表現による設定)
    'allowed_origins_patterns' => [],

    // 許可されるヘッダー設定
    'allowed_headers' => ['*'],

    // カスタムヘッダーを公開する
    'exposed_headers' => [],

    // CORSレスポンスのキャッシュ
    'max_age' => 0,

    // CORSによるHTTPセッション
    'supports_credentials' => false,
];

上記の方法で追加することができましたが、「Lumen」のバージョンが10の場合にエラーが出ました。
原因は「laravel-cors」がLumen10に対応していないことが原因でした。
もしエラーとなる場合はLumenのバージョンを9にするといいかもしれません。