跨域资源共享 (CORS)

在 4.5.0 版本加入.

跨域资源共享 (CORS) 是一种基于 HTTP 头的安全机制,允许服务器指示浏览器应允许从其自身以外的任何来源(域名、协议或端口)加载资源。

CORS 通过在 HTTP 请求和响应中添加头来工作,以指示请求的资源是否可以跨不同来源共享,从而帮助防止恶意攻击,如跨站请求伪造 (CSRF) 和数据盗窃。

如果你不熟悉 CORS 和 CORS 头,请阅读 MDN 上的 CORS 文档

CodeIgniter 提供了 CORS 过滤器和 helper 类。

配置 CORS

设置默认配置

可以通过 app/Config/Cors.php 配置 CORS。

至少需要设置 $default 属性中的以下项目:

  • allowedOrigins: 明确列出你想要允许的来源。

  • allowedHeaders: 明确列出你想要允许的 HTTP 头。

  • allowedMethods: 明确列出你想要允许的 HTTP 方法。

警告

基于最小特权原则,只应允许必要的最小来源、方法和头。

如果你在跨域请求中发送凭证(例如,cookies),请将 supportsCredentials 设置为 true

启用 CORS

要启用 CORS,你需要做两件事:

  1. 为允许 CORS 的路由指定 cors 过滤器。

  2. 为 CORS 预检请求添加 OPTIONS 路由。

设置路由

你可以在 app/Config/Routes.php 中为路由设置 cors 过滤器。

例如,

<?php

use CodeIgniter\Router\RouteCollection;

$routes->group('', ['filter' => 'cors'], static function (RouteCollection $routes): void {
    $routes->resource('product');

    $routes->options('product', static function () {
        // Implement processing for normal non-preflight OPTIONS requests,
        // if necessary.
        $response = response();
        $response->setStatusCode(204);
        $response->setHeader('Allow:', 'OPTIONS, GET, POST, PUT, PATCH, DELETE');

        return $response;
    });
    $routes->options('product/(:any)', static function () {});
});

不要忘记为预检请求添加 OPTIONS 路由。因为如果路由不存在,控制器过滤器(必需过滤器除外)将不起作用。

CORS 过滤器处理所有预检请求,因此通常不会调用 OPTIONS 路由的闭包控制器。

在 Config\Filters 中设置

或者,你可以在 app/Config/Filters.php 中为 URI 路径设置 cors 过滤器。

例如,

<?php

namespace Config;

use CodeIgniter\Config\Filters as BaseFilters;

// ...

class Filters extends BaseFilters
{
    // ...
    public array $filters = [
        // ...
        'cors' => [
            'before' => ['api/*'],
            'after'  => ['api/*'],
        ],
    ];
}

不要忘记为预检请求添加 OPTIONS 路由。因为如果路由不存在,控制器过滤器(必需过滤器除外)将不起作用。

例如,

<?php

use CodeIgniter\Router\RouteCollection;

$routes->group('', ['filter' => 'cors'], static function (RouteCollection $routes): void {
    $routes->options('api/(:any)', static function () {});
});

CORS 过滤器处理所有预检请求,因此通常不会调用 OPTIONS 路由的闭包控制器。

检查路由和过滤器

配置完成后,你可以使用 spark 路由 命令检查路由和过滤器。

设置其他配置

如果你想使用不同于默认配置的配置,请在 app/Config/Cors.php 中添加一个属性。

例如,添加 $api 属性。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

/**
 * Cross-Origin Resource Sharing (CORS) Configuration
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
 */
class Cors extends BaseConfig
{
    // ...

    public array $api = [
        'allowedOrigins'         => ['https://app.example.com'],
        'allowedOriginsPatterns' => [],
        'supportsCredentials'    => true,
        'allowedHeaders'         => ['Authorization', 'Content-Type'],
        'exposedHeaders'         => [],
        'allowedMethods'         => ['GET', 'POST', 'PUT', 'DELETE'],
        'maxAge'                 => 7200,
    ];
}

属性名称(在上述示例中为 api)将成为配置名称。

然后,像 cors:api 一样将属性名称指定为过滤器参数:

<?php

use CodeIgniter\Router\RouteCollection;

$routes->group('api', ['filter' => 'cors:api'], static function (RouteCollection $routes): void {
    $routes->resource('user');

    $routes->options('user', static function () {});
    $routes->options('user/(:any)', static function () {});
});

你也可以使用 过滤器参数

类参考

class CodeIgniter\HTTP\Cors
CodeIgniter\HTTP\Cors::addResponseHeaders(RequestInterface $request, ResponseInterface $response) ResponseInterface
参数:
  • $request (RequestInterface) – 请求实例

  • $response (ResponseInterface) – 响应实例

返回:

响应实例

返回类型:

ResponseInterface

添加 CORS 的响应头。

CodeIgniter\HTTP\Cors::handlePreflightRequest(RequestInterface $request, ResponseInterface $response) ResponseInterface
参数:
  • $request (RequestInterface) – 请求实例

  • $response (ResponseInterface) – 响应实例

返回:

响应实例

返回类型:

ResponseInterface

处理预检请求。

CodeIgniter\HTTP\Cors::isPreflightRequest(IncomingRequest $request) bool
参数:
返回:

如果是预检请求则返回 True。

返回类型:

bool

检查请求是否为预检请求。