Activer le CORS sur CakePHP v3.x – Pratique

Si vous maitrisez les principes du CORS nous allons maintenant activer cette fonctionnalité dans notre framework préféré.

Jusqu’à présent (c’est à dire avant CakePHP v3.3)  il y’avait 3 possibilités :

  • Dans le bootstrap.php, nous rajoutions à la barbare un gros header(« Access-Control-Allow-Origin: * »)
  • Tout aussi bourrin, ce header pouvait être mis dans la classe de base AppController
  • De façon plus fine, nous pouvions créer un Dispatch Filter (voir à ce sujet un post sur ce blog)

Depuis CakePHP v3.3 nous pouvons utiliser une caractéristique du PSR7 : les middlewares (voir la doc à ce sujet). Le middleware est un stack qui est traité en amont du traitement de tous les controllers, le middleware ne traite que la partie « Requête » et « Réponse » de votre application CakePHP (les partisans du Framework Express de NodeJS sont habitués aux middlewares).

C’est dans cette couche middleware que nous renverrons notre header « Access-Control-Allow-Origin ». Avec CakePHP v3.3, les middlewares sont déclarés dans le répertoire « src/Application.php », les middlewares par défaut sont :

$middleware
->add(new ErrorHandlerMiddleware(Configure::read('Error.exceptionRenderer')))// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware())
->add(new RoutingMiddleware());// Apply routing

Nous allons donc rajouter un middleware supplémentaire qui va modifier la réponse envoyée au client pour lui ajouter le CORS :

$middleware
->add(function (RequestInterface $request, ResponseInterface $response, $next) {
    $response = $next($request, $response);
    if ($request->getMethod() == "OPTIONS") {
        $method = $request->getHeader('Access-Control-Request-Method');
        $headers = $request->getHeader('Access-Control-Request-Headers');
        $response = $response->withHeader('Access-Control-Allow-Headers', $headers);
        $response = $response->withHeader('Access-Control-Allow-Methods', empty($method) ? 'GET, POST, PUT, DELETE' : $method);
        $response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
        $response = $response->withHeader('Access-Control-Max-Age', '120');
        $response->send();
    } else {
        $response = $response->withHeader('Access-Control-Allow-Origin', '*')
                             ->withHeader('Access-Control-Allow-Credentials', 'true')
                             ->withHeader('Access-Control-Max-Age', '86400');
    }
    return $response;
})

Avec ce code nous indiquons au client que les types de requêtes « GET, POST, PUT, DELETE » sont autorisés en CORS (lors du preflight), puis nous renvoyons systématiquement un « Access-Control-Allow-Origin » autorisé à partir de tout les domaines :

$response = $response->withHeader('Access-Control-Allow-Origin', '*')

Si nous voulions limiter le domaine source, nous pourrions remplacer le * par le domaine que nous autorisons.

Et voilà, le CORS est maintenant activé !

Quelle sera la prochaine étape ? Pour le CORS plus rien, mais vous aurez compris que l’utilisation du CORS n’a d’intérêt que si vous publiez des API RESTs par exemple. Le prochain article aura donc comme objectif de créer une API REST complète et de gérer les autorisations d’API via le protocole d’accès JWT (Json Web Token). Puis nous terminerons pas un cas pratique d’utilisation d’un client Angular2/Ionic2 pour créer une application mobile iOS / Android avec CakePHP comme backend !

Un joli programme en perspective, restez à l’écoute !

Comme d’habitude, si vous avez un souci ou une question, n’hésitez pas à me contacter par mail, à laisser un commentaire ou à poster directement sur le forum de la communauté francophone (même si je n’y suis plus souvent).

L’image de l’article est tirée du blog Inovia

Comments: 2

    • cyberbobjr says:

      Salut,
      Bien vu, merci pour ton partage ?
      Pour l’écriture, entre CakePHP, Angular2, NodeJs, Ionic2, SWIFT, etc. mon temps de dispo s’est réduit drastiquement ?

      ++
      Ben

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *