Skip to content

Instantly share code, notes, and snippets.

@Digi92
Last active December 18, 2023 22:58
Show Gist options
  • Save Digi92/1c2565c2fc420b3d3e65b89dbbdff162 to your computer and use it in GitHub Desktop.
Save Digi92/1c2565c2fc420b3d3e65b89dbbdff162 to your computer and use it in GitHub Desktop.
Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application. This event subscriber is used to handle CORS Preflight OPTIONS requests. It enables the application to accept requests from the domain specified in 'app.frontend_
<?php
declare(strict_types=1);
namespace App\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* This event subscriber is used to handle CORS Preflight OPTIONS requests.
* It enables the application to accept requests from the domain specified in 'app.frontend_app_host'
* by placing the corresponding CORS headers in the response..
* This is necessary to enable communication between the frontend and the backend in a
* cross-origin situation.
* Docs: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
*
* Class CorsSubscriber
* @package App\EventSubscriber
*/
class CorsSubscriber implements EventSubscriberInterface
{
private RouterInterface $router;
private ParameterBagInterface $params;
public function __construct(RouterInterface $router, ParameterBagInterface $params)
{
$this->router = $router;
$this->params = $params;
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 250],
KernelEvents::RESPONSE => ['onKernelResponse', 0]
];
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
// Check if this is a preflight request
if ($event->isMainRequest() &&
'OPTIONS' === $request->getRealMethod() &&
$request->headers->has('Access-Control-Request-Method') &&
in_array(
$request->headers->get('Access-Control-Request-Method'),
['HEAD','GET','POST','PUT','PATCH','DELETE','PURGE','OPTIONS','TRACE','CONNECT']
)
) {
// We must overwrite the RequestContext method value with the method of 'Access-Control-Request-Method',
// otherwise routes that do not allow GET cannot be found.
$originalContextMethod = $this->router->getContext()->getMethod();
$this->router->setContext(
$this->router->getContext()->setMethod($request->headers->get('Access-Control-Request-Method'))
);
// Try to find the route and set the correct Access-Control-Allow header
if (is_array($matchedRoute = $this->router->match($request->getPathInfo())) &&
isset($matchedRoute['_route']) &&
($route = $this->router->getRouteCollection()->get($matchedRoute['_route'])) instanceof Route
) {
$allowedOrigin = '*';
if ($this->params->has('app.frontend_app_host')) {
$allowedOrigin = $this->params->get('app.frontend_app_host');
}
// Get allowed methods from loaded route
$allowedMethods = $route->getMethods();
$response = new Response();
$response->headers->set('Access-Control-Allow-Origin', $allowedOrigin);
$response->headers->set('Access-Control-Allow-Headers', 'Accept, Authorization, X-AUTH-TOKEN');
$response->headers->set('Access-Control-Allow-Methods', implode(', ', $allowedMethods));
$event->setResponse($response);
}
// Restore the original router context method.
// This should only be the case if the route is invalid
$this->router->setContext(
$this->router->getContext()->setMethod($originalContextMethod)
);
}
}
public function onKernelResponse(ResponseEvent $event): void
{
// Skip all not main requests
if ($event->isMainRequest()) {
$allowedOrigin = '*';
if ($this->params->has('app.frontend_app_host')) {
$allowedOrigin = $this->params->get('app.frontend_app_host');
}
$response = $event->getResponse();
$response->headers->set('Access-Control-Allow-Origin', $allowedOrigin);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment