Fonctionnement des API

Bonjour,

J’aimerais comprendre le fonctionnement des API YesWiki.
Nous avons une route existante provenant de YW retournant les données d’un formulaire (/api/forms/ID) et les données sont uniquement accessible par quelqu’un de connecté sur le site qui est également dans le groupe admin.
Nous souhaiterions ouvrir cette API via un système d’authentification (type token ID, bearer…).

Bonjour,
effectivement, le fonctionnement de la personnalisation des routes api n’est peut être pas explicite.
Je vais donné ici des astuces qui pourraient être documentées dans la doc officielle (visible ici et modifiable )

Pour se connecter à une route api avec un bearer, il faut:

  1. ajouter le paramètre suivant dans le fichier wakka.config.php
   'api_allowed_keys' => [
      'UserName1' => 'a-complex-token-1',
      'UserName2' => 'a-complex-token-2',
   ],
  1. placer les utilisateurs UserName1 et UserName2 dans des groupes avec les accès souhaités
  2. faire un appel sur la route api avec l’en-tête HTTP Authorization: Bearer a-complex-token-1
    Ceci connectera automatiquement l’utilisateur concerné

Une autre méthode est d’appeler la route concernée avec les bons cookies. Par exemple,

  1. se connecter via une requête POST sur une page de connexion /?ParametresUtilisateur avec name=UserName&password=real-password&action=login
  2. puis faire une requête api dans le même contexte (les cookies devraient être envoyés automatiquement permettant de maintenir la connexion).

NB : il n’existe pas actuellement de route api, permettant une connexion aisée

Bons tests

et si ça peut aider : je rajoute ceci :

Il est possible de créer de nouvelles routes api en créant le fichier custom/controllers/ApiController.php. Celui ci doit contenir quelque chose du type :

<?php

namespace YesWiki\Custom\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use YesWiki\Core\ApiResponse;
use YesWiki\Core\YesWikiController;

class ApiController extends YesWikiController
{
    /**
     * @Route("/api/my/route/{name}",methods={"GET"}, options={"acl":{"public"}},priority=2)
     */
    public function myRoute($name)
        // do something
        return new ApiResponse(['result'=>$name],Response::HTTP_OK);
    }
}

Si l’objectif est de remplacer une route existante dans YesWiki, alors identifier le fichier ApiController.php où est définie la route. Par exemple, pour la route api/forms/{id}, le code est défini ICI.

  1. recopier l’en-tête de la méthode et la méthode pour la ré-écrire
    Dans notre exemple,
/**
 * @Route("/api/forms/{formId}", methods={"GET"},options={"acl":{"public"}})
 * @Route("/api/forms/{formId}/", methods={"GET"},options={"acl":{"public"}})
 */
public function getForm($formId)
{
    ....
    return new ApiResponse($form);
}
  1. Rajouter un paramètre de priorité sans modifier l’option des acl :
/**
 * @Route("/api/forms/{formId}", methods={"GET"},options={"acl":{"public"}},priority=2)
 * @Route("/api/forms/{formId}/", methods={"GET"},options={"acl":{"public"}},priority=2)
 */
public function getForm($formId)
{
    ....
    return new ApiResponse($form);
}

(plus la priorité est forte, plus la route sera celle retenue en priorité si plusieurs routes identiques sont définies dans le code).
3. ajouter le code nécessaire pour rajouter des droits d’accès plus forts en appelant ensuite la fonction d’origine (attention le code proposé ci-dessous fonctionne parce que Bazar/ApiController a été enregistré comme service via tools/bazar/config.yaml

<?php

namespace YesWiki\Custom\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use YesWiki\Bazar\Controller\ApiController as BazarApiController;
use YesWiki\Core\ApiResponse;
use YesWiki\Core\Service\AclService;
use YesWiki\Core\YesWikiController;

class ApiController extends YesWikiController
{   
    /**
     * @Route("/api/forms/{formId}", methods={"GET"},options={"acl":{"public"}},priority=2)
     * @Route("/api/forms/{formId}/", methods={"GET"},options={"acl":{"public"}},priority=2)
     */
    public function getForm($formId)
        $bazarApiController = $this->getService(BazarApiController::class);
        $aclService = $this->getService(AclService::class);
        $wantedId = 3;  // choose the right id
        if ($formId == $wantedId){
             if (!$aclService->check('@wantedGroup')){ // admins will be included by default
                  return new ApiResponse([],Response::HTTP_UNAUTHORIZED);
             }
        }
        return $bazarApiController->getForm($name);
    }
}

Ceci permet d’ouvrir l’accès à certaines données