tuupola/cors-middleware

PSR-7 和 PSR-15 CORS 中间件

1.4.3 2022-10-11 11:29 UTC

README

此中间件实现了跨源资源共享。它支持 PSR-7 风格的双遍历和 PSR-15 中间件标准。它已经与 Slim 框架Zend Expressive 进行了测试。内部中间件使用 neomerx/cors-psr7 库进行重负载。

Latest Version Packagist Software License Build Status Coverage

安装

使用 composer 进行安装。

$ composer require tuupola/cors-middleware

用法

文档假设您已具备 CORS 的基本知识。没有强制参数。如果您使用 Zend Expressive,则中间件将添加到名为 config/pipeline.php 的文件中。请注意,您必须禁用默认的 ImplicitOptionsMiddleware 以使此中间件正常工作。

use Tuupola\Middleware\CorsMiddleware;

#$app->pipe(ImplicitOptionsMiddleware::class);
$app->pipe(CorsMiddleware::class);

Slim 框架没有指定配置文件。否则添加中间件的方式与之前类似。

$app->add(new Tuupola\Middleware\CorsMiddleware);

其余示例使用 Slim 框架。

如果没有传递任何参数,将使用以下默认值。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*"],
    "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
    "headers.allow" => [],
    "headers.expose" => [],
    "credentials" => false,
    "cache" => 0,
]));
$ curl "https://api.example.com/" \
    --request OPTIONS \
    --include
    --header "Access-Control-Request-Method: PUT" \
    --header "Origin: http://www.example.com"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE

但是,您可能希望更改一些默认值。例如,如果您正在开发支持缓存和条件请求的 REST API,则可以使用以下示例。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*"],
    "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
    "headers.allow" => ["Authorization", "If-Match", "If-Unmodified-Since"],
    "headers.expose" => ["Etag"],
    "credentials" => true,
    "cache" => 86400
]));
$ curl "https://api.example.com/foo" \
    --request OPTIONS \
    --include \
    --header "Origin: http://www.example.com" \
    --header "Access-Control-Request-Method: PUT" \
    --header "Access-Control-Request-Headers: Authorization, If-Match"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Max-Age: 86400
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
Access-Control-Allow-Headers: authorization, if-match, if-unmodified-since
$ curl "https://api.example.com/foo" \
    --request PUT \
    --include \
    --header "Origin: http://www.example.com"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Expose-Headers: Etag

参数

默认情况下,允许所有源。您可以通过将它们作为数组传递来限制允许的源。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["app-1.example.com", "app-2.example.com"]
]));

您还可以使用通配符一次性定义多个源。通配符通过使用 fnmatch() 函数进行匹配。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*.example.com"]
]));

方法

方法可以是数组或可调用函数,该函数返回一个数组。以下示例用于 Zend Expressive,其中 methods 的值取决于请求的路由。

use Tuupola\Middleware\CorsMiddleware;
use Zend\Expressive\Router\RouteResult;

$app->pipe(new CorsMiddleware([
    "origin" => ["*"],
    "methods" => function($request) {
        $result = $request->getAttribute(RouteResult::class);
        $route = $result->getMatchedRoute();
        return $route->getAllowedMethods();
    }
]));

Slim 3 的用法与此类似。这假设您尚未定义 OPTIONS 路由。

use Fastroute\Dispatcher;
use Tuupola\Middleware\CorsMiddleware;

$app->add(
    new CorsMiddleware([
        "origin" => ["*"],
        "methods" => function($request) use ($app) {
            $container = $app->getContainer();
            $dispatch = $container["router"]->dispatch($request);
            if (Dispatcher::METHOD_NOT_ALLOWED === $dispatch[0]) {
                return $dispatch[1];
            }
        }
    ])
);

日志记录器

可选的 logger 参数允许您传递一个 PSR-3 兼容的日志记录器,以帮助进行调试或其他应用程序日志记录需求。

$logger = Monolog\Logger("slim");
$rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG);
$logger->pushHandler($rotating);

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "logger" => $logger,
]));

错误

当 CORS 请求失败时调用错误。它接收最后错误消息作为参数。这可以用于在 CORS 请求失败时创建 application/json 响应。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "methods" => ["GET", "POST", "PUT"],
    "error" => function ($request, $response, $arguments) {
        $data["status"] = "error";
        $data["message"] = $arguments["message"];
        return $response
            ->withHeader("Content-Type", "application/json")
            ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
    }
]));
$ curl https://api.example.com/foo \
    --request OPTIONS \
    --include \
    --header "Access-Control-Request-Method: PATCH" \
    --header "Origin: http://www.example.com"

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 83

{
    "status": "error",
    "message": "CORS requested method is not supported."
}

服务器源

如果您的同源请求包含不必要的 Origin 标头,它们可能会在服务器源不在已允许的源列表中被阻塞的情况下被阻止。在这种情况下,您可以使用可选的 origin.server 参数来指定服务器的源。

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin.server" => "https://example.com"
]));
$ curl https://example.com/api \
    --request POST \
    --include \
    --header "Origin: https://example.com"

HTTP/1.1 200 OK

测试

您可以手动或自动运行测试,每次代码更改时都自动运行。自动测试需要 entr 工作。

$ make test
$ brew install entr
$ make watch

贡献

请参阅 CONTRIBUTING 以获取详细信息。

安全

如果您发现任何与安全相关的问题,请通过电子邮件 tuupola@appelsiini.net 而不是使用问题跟踪器。

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件