Переглянути джерело

add the CORS tool add on .env CORS=true/false

gdias 1 місяць тому
батько
коміт
9e09a5bd50
2 змінених файлів з 90 додано та 1 видалено
  1. 85 0
      middlewares/CorsMiddleware.php
  2. 5 1
      public/index.php

+ 85 - 0
middlewares/CorsMiddleware.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace Middlewares;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use React\Http\Message\Response;
+use React\Promise\PromiseInterface;
+
+class CorsMiddleware
+{
+    private ?string $forcedOrigin;
+
+    public function __construct()
+    {
+        $origin = $_ENV['CORS_ALLOWED_ORIGIN'] ?? '';
+        $this->forcedOrigin = $origin !== '' ? $origin : null;
+    }
+
+    public function __invoke(ServerRequestInterface $request, callable $next)
+    {
+        $origin = $this->resolveOrigin($request);
+
+        if (strtoupper($request->getMethod()) === 'OPTIONS') {
+            return $this->preflightResponse($origin);
+        }
+
+        $response = $next($request);
+
+        return $this->decorateResponse($response, $origin);
+    }
+
+    /**
+     * @param ResponseInterface|PromiseInterface $response
+     * @return ResponseInterface|PromiseInterface
+     */
+    private function decorateResponse($response, string $origin)
+    {
+        if ($response instanceof PromiseInterface) {
+            return $response->then(function ($actual) use ($origin) {
+                return $this->decorateResponse($actual, $origin);
+            });
+        }
+
+        if ($response instanceof ResponseInterface) {
+            return $this->applyHeaders($response, $origin);
+        }
+
+        return $response;
+    }
+
+    private function preflightResponse(string $origin): ResponseInterface
+    {
+        return $this->applyHeaders(
+            Response::plaintext('')->withStatus(204),
+            $origin
+        );
+    }
+
+    private function applyHeaders(ResponseInterface $response, string $origin): ResponseInterface
+    {
+        $response = $response
+            ->withHeader('Access-Control-Allow-Origin', $origin)
+            ->withHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
+            ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
+            ->withHeader('Access-Control-Max-Age', '86400')
+            ->withHeader('Vary', 'Origin');
+
+        if ($origin !== '*') {
+            $response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
+        }
+
+        return $response;
+    }
+
+    private function resolveOrigin(ServerRequestInterface $request): string
+    {
+        if ($this->forcedOrigin !== null) {
+            return $this->forcedOrigin;
+        }
+
+        $origin = $request->getHeaderLine('Origin');
+        return $origin !== '' ? $origin : '*';
+    }
+}

+ 5 - 1
public/index.php

@@ -3,6 +3,7 @@
 require __DIR__ . '/../vendor/autoload.php';
 
 use FrameworkX\App;
+use Middlewares\CorsMiddleware;
 use Middlewares\JwtAuthMiddleware;
 
 $requestUri = $_SERVER['REQUEST_URI'] ?? null;
@@ -33,7 +34,10 @@ $dbPass = $_ENV['DB_PASSWORD'] ?? '';
 $GLOBALS['pdo'] = new \PDO($dsn, $dbUser, $dbPass);
 $GLOBALS['pdo']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
 
-$app = new App();
+$corsEnabled = filter_var($_ENV['CORS'] ?? 'false', FILTER_VALIDATE_BOOLEAN);
+$globalMiddleware = $corsEnabled ? [CorsMiddleware::class] : [];
+
+$app = new App(...$globalMiddleware);
 $authJwt = new JwtAuthMiddleware();
 
 $app->post('/verify/jwt', $authJwt,\Controllers\HelloController::class);