| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 |
- <?php
- namespace Middlewares;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use React\Http\Message\Response;
- use React\Promise\PromiseInterface;
- /**
- * CORS global da API.
- *
- * Registrado como middleware GLOBAL (no construtor do App em public/index.php),
- * portanto roda antes do roteamento. Isso é essencial para responder ao
- * preflight `OPTIONS` — que não possui rota registrada e, sem este middleware,
- * cairia em 404 antes do navegador concluir a requisição real.
- *
- * Política atual: liberar todas as origens (`*`). Como usamos "*", NÃO enviamos
- * `Access-Control-Allow-Credentials` (o navegador rejeita a combinação) — a
- * autenticação é via header `Authorization: Bearer`, não via cookie, então isso
- * não é um problema.
- */
- final class CorsMiddleware
- {
- public function __invoke(ServerRequestInterface $request, callable $next)
- {
- // Preflight: responde imediatamente, sem chegar ao roteador/controllers.
- if (strtoupper($request->getMethod()) === 'OPTIONS') {
- return $this->withCorsHeaders(new Response(204));
- }
- $response = $next($request);
- // Controllers respondem de forma síncrona (Response), mas o FrameworkX
- // também aceita Promise. Tratamos ambos para anexar os headers de CORS.
- if ($response instanceof PromiseInterface) {
- return $response->then(fn (ResponseInterface $resolved): ResponseInterface => $this->withCorsHeaders($resolved));
- }
- return $this->withCorsHeaders($response);
- }
- private function withCorsHeaders(ResponseInterface $response): ResponseInterface
- {
- return $response
- ->withHeader('Access-Control-Allow-Origin', '*')
- ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
- ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Unipile-Auth, Unipile-Notify-Secret')
- ->withHeader('Access-Control-Max-Age', '86400');
- }
- }
|