i-TegoDocumentationAuthentification > OpenID Connect OAuth Serveur dédié > Développer > Adaptation des applications > Techniques et code du serveur OAuthSD

API HTTP REST

  (publié initialement le jeudi 7 mars 2019) par DnC

OAuthSD expose une API HTTP REST qui permet d’automatiser certaines tâches autour du serveur d’authentification. Une application d’administration (supervision) peut ainsi contrôler les données du serveur.
L’API s’appuie sur HTTPFoundation de Symphony. Les objets sont manipulés au format Collection+JSON ou sous un format json simple.

Remarque : Il existe également une API HTTP REST + TreeQL.

L’API répond à une unique action « http.api » qui va gérer trois paramètres :

- un format : c’est le nom de l’API réellement implémentée : json, collectionjson.
- un type (ou une collection) : le type des données qu’on veut utiliser : auteurs, users, clients ...
- une ressource : l’identifiant unique d’un contenu (un nombre entier).

Ces trois paramètres sont tout simplement ajoutés à la suite dans l’URL, séparés par des « / ». Seul le premier est toujours obligatoire, les autres sont ajoutés suivant ce que l’on veut manipuler. On se retrouve alors avec trois familles d’Url de requêtes.

Exemple de requête d’action :

https://oa.dnc.global/web/http.api/collectionjson/users/3

La deuxième forme peut également être complétée par des paramètres d’URL. Exemple :

Exemple de requête avec paramètres :

https://oa.dnc.global/web/http.api/collectionjson/users/?offset=10&length=10

L’API permet d’effectuer les opérations CRUD [1] sur une table de la base de données en fonction de la méthode de la requête HTTP GET, POST, PUT ou DELETE, si toutefois les permissions sont accordées.

L’API s’efforce de répondre à la spécification de sémantique HTTP 1.1.

Types

Pour s’interfacer avec une application de supervision, OAuth SD expose les types :
- oidc_logs,
- users,
- clients
- auteurs.
D’une façon générale, les types correspondent aux tables éponymes.
Sauf exception (voir la constante de configuration API_HTTP_CHAMPS_SENSIBLES), tous les champs d’une table peuvent être manipulés.

Formats

Dans le cadre d’OAuthSD, les objets sont manipulés aux formats suivants :

collectionjson
Ce format est assez lourd, retournant les données sous forme d’arrays associatifs et d’objets, ce qui permet de nombreuses applications. Voir : Collection+JSON.

Exemple : la requête :

https://oa.dnc.global/web/http.api/collectionjson/oidc_logs/?offset=3000&length=2

retourne :

  1. {
  2.   "collection": {
  3.     "version": "1.0",
  4.     "href": "https://oa.dnc.global/web/http.api/collectionjson/oidc_logs/?offset=3000&length=2",
  5.     "items": [
  6.       {
  7.         "href": "https://oa.dnc.global/web/http.api/collectionjson/",
  8.         "links": [
  9.           {
  10.             "rel": "edit",
  11.             "href": "https://oa.dnc.global/web/http.api/collectionjson/"
  12.           },
  13.           {
  14.             "rel": "alternate",
  15.             "type": "text/html",
  16.             "href": "https://oa.dnc.global/web/urls_propres2_dist"
  17.           }
  18.         ],
  19.         "data": [
  20.           {
  21.             "name": "id_oidc_log",
  22.             "value": "3400"
  23.           },
  24.           {
  25.             "name": "remote_addr",
  26.             "value": "173.208.157.186"
  27.           },
  28.           {
  29.             "name": "state",
  30.             "value": ""
  31.           },
  32.           {
  33.             "name": "client_id",
  34.             "value": "testopenid4"
  35.           },
  36.           {
  37.             "name": "user_id",
  38.             "value": "Unk"
  39.           },
  40.           {
  41.             "name": "datetime",
  42.             "value": "2019-03-06 03:04:09"
  43.           },
  44.           {
  45.             "name": "origin",
  46.             "value": "Authorize"
  47.           },
  48.           {
  49.             "name": "message",
  50.             "value": "2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin\n\n"
  51.           },
  52.           {
  53.             "name": "level",
  54.             "value": "1"
  55.           },
  56.           {
  57.             "name": "weight",
  58.             "value": "0"
  59.           },
  60.           {
  61.             "name": "errnum",
  62.             "value": "1"
  63.           }
  64.         ]
  65.       },
  66.       {
  67.         "href": "https://oa.dnc.global/web/http.api/collectionjson/",
  68.         "links": [
  69.           {
  70.             "rel": "edit",
  71.             "href": "https://oa.dnc.global/web/http.api/collectionjson/"
  72.           },
  73.           {
  74.             "rel": "alternate",
  75.             "type": "text/html",
  76.             "href": "https://oa.dnc.global/web/urls_propres2_dist"
  77.           }
  78.         ],
  79.         "data": [
  80.           {
  81.             "name": "id_oidc_log",
  82.             "value": "3401"
  83.           },
  84.           {
  85.             "name": "remote_addr",
  86.             "value": "173.208.157.186"
  87.           },
  88.           {
  89.             "name": "state",
  90.             "value": "fc06ce8d03c189c7af1167d2e16e4a9a"
  91.           },
  92.           {
  93.             "name": "client_id",
  94.             "value": "testopenid4"
  95.           },
  96.           {
  97.             "name": "user_id",
  98.             "value": "Unk"
  99.           },
  100.           {
  101.             "name": "datetime",
  102.             "value": "2019-03-06 03:04:09"
  103.           },
  104.           {
  105.             "name": "origin",
  106.             "value": "Authorize"
  107.           },
  108.           {
  109.             "name": "message",
  110.             "value": "2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin authentification for client = testopenid4\n\n"
  111.           },
  112.           {
  113.             "name": "level",
  114.             "value": "1"
  115.           },
  116.           {
  117.             "name": "weight",
  118.             "value": "1"
  119.           },
  120.           {
  121.             "name": "errnum",
  122.             "value": "110"
  123.           }
  124.         ]
  125.       }
  126.     ],
  127.     "objects": [
  128.       {
  129.         "id_oidc_log": "3400",
  130.         "remote_addr": "173.208.157.186",
  131.         "state": "",
  132.         "client_id": "testopenid4",
  133.         "user_id": "Unk",
  134.         "datetime": "2019-03-06 03:04:09",
  135.         "origin": "Authorize",
  136.         "message": "2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin\n\n",
  137.         "level": "1",
  138.         "weight": "0",
  139.         "errnum": "1"
  140.       },
  141.       {
  142.         "id_oidc_log": "3401",
  143.         "remote_addr": "173.208.157.186",
  144.         "state": "fc06ce8d03c189c7af1167d2e16e4a9a",
  145.         "client_id": "testopenid4",
  146.         "user_id": "Unk",
  147.         "datetime": "2019-03-06 03:04:09",
  148.         "origin": "Authorize",
  149.         "message": "2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin authentification for client = testopenid4\n\n",
  150.         "level": "1",
  151.         "weight": "1",
  152.         "errnum": "110"
  153.       }
  154.     ]
  155.   }
  156. }

Télécharger

Format json
Retourne un simple array. Exemple : la requête :

https://oa.dnc.global/web/http.api/json/oidc_logs/?offset=3000&length=2

retourne les mêmes éléments sous une forme très compacte :

  1. [
  2. {"id_oidc_log":"3400","remote_addr":"173.208.157.186","state":"","client_id":"testopenid4","user_id":"Unk","datetime":"2019-03-06 03:04:09","origin":"Authorize","message":"2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin","level":"1","weight":"0","errnum":"1"}
  3. ,
  4. {"id_oidc_log":"3401","remote_addr":"173.208.157.186","state":"fc06ce8d03c189c7af1167d2e16e4a9a","client_id":"testopenid4","user_id":"Unk","datetime":"2019-03-06 03:04:09","origin":"Authorize","message":"2019-03-06 03:04:09 - 173.208.157.186 - Information : Authorize : Begin authentification for client = testopenid4",
  5. "level":"1","weight":"1","errnum":"110"}
  6. ]

Télécharger

Le format collectionjson est intéressant en lecture. En écriture, on préférera le format json qui suffit à décrire les objets à enregistrer.

Actions

Suivant le paradigme HTTP Rest, les actions découlent de la méthode HTTP utilisée pour appeler l’API : get, post, put ou delete.

Formes générales des requêtes GET

- Afficher la liste des collections disponibles sous le format indiqué :

https://oa.dnc.global/web/http.api/<format>

- Liste le contenu de la collection "type" :

https://oa.dnc.global/web/http.api/<format>/<type>

- Liste les éléments sélectionnés à l’aide des paramètres d’URL indiqués :

https://oa.dnc.global/web/http.api/<format>/<type>?<paramètres>

- Accès à une ressource précise :

https://oa.dnc.global/web/http.api/collectionjson/<type>/NN

NN est la valeur de l’identifiant (champ id_type, clé unique) de l’enregistrement dans la table.

Requêtes avec POST, PUT et DELETE

Ces requêtes doivent être générées programmatiquement : par exemple avec cURL côté serveur ou en Javascript côté client. On trouve couramment des bibliothèque exposant des fonctions de ce type :

- post_collection($requete, $reponse)
Créer une nouvelle ressource dans la collection (créer un nouvel enregistrement dans la table).

- put_ressource($requete, $reponse)
Ce cas est sensiblement le même que le précédent, à ceci près que l’on travaille sur la modification d’une ressource précise.

- delete_ressource($requete, $reponse)
Supprimer définitivement une ressource.

Pour la transmission des données aux requêtes avec POST et PUT, deux formats sont possibles :
- application/json :

  1. $data = array(
  2.     'client_id' => 'testtest',
  3.     'client_secret' => 'TheBigSecret',
  4.     'redirect_uri' => 'https://oa.dnc.global/web/?action=oauth',
  5.     'grant_types' => 'authorization_code',
  6.     'scope' => 'openid sli',
  7. );
  8.  
  9. $h = curl_init("https://oa.dnc.global/web/http.api/json/clients/");
  10. curl_setopt($h, CURLOPT_RETURNTRANSFER, true);
  11. curl_setopt($h, CURLOPT_TIMEOUT, 10);
  12. curl_setopt($h, CURLOPT_POST, true);
  13. $data_string = json_encode($data);  
  14. curl_setopt($h, CURLOPT_POSTFIELDS, $data_string);
  15. curl_setopt($h, CURLOPT_HTTPHEADER, array(                                                                          
  16.     'Content-Type: application/json',                                                                                
  17.     'Content-Length: ' . strlen($data_string),
  18.     'Accept: application/json')                                                    
  19. );

Télécharger

- application/x-www-form-urlencoded :

  1. ...
  2. curl_setopt($h, CURLOPT_HTTPHEADER, array(
  3.     'Content-Type: application/x-www-form-urlencoded',
  4.      'Accept: application/json')
  5. );  
  6. curl_setopt($h, CURLOPT_POSTFIELDS, http_build_query($data));

Télécharger

Actions possibles

Toutes les combinaisons format/type/action ne sont pas disponibles.

En premier lieu, l’accès à l’API est subordonné à l’authentification de l’application cliente et de l’utilisateur final par OAuthSD.

Ensuite, toutes les combinaisons type/action ne sont pas autorisées. Des droits sont définis pour chaque action en fonction du profil de l’auteur (administrateur d’applications) authentifié.

Enfin, certaines actions ne sont pas (ou pas encore) implémentées.

Protection des données

Les données très sensibles (conditionnant la sécurité de l’authentification) sont protégées, elles ne peuvent être vues ni a fortiori modifiées à l’aide de l’API.

Dans l’état actuel, les champs suivants, définis par la constante API_HTTP_CHAMPS_SENSIBLES, ne sont pas transmis : client_secret, client_ip, password’.

clients (Applications clientes)

Requêtes GET

Le type clients permet de nombreuses requêtes GET avec les formats collectionjson et json, notamment avec les paramètres offset et length. La requête suivante est pratique pour générer des tableaux paginés :

https://oa.dnc.global/web/http.api/collectionjson/clients/?offset=100&length=10

Pour assurer la sécurité de l’authentification :
- les donnée sensibles "client_secret" et "client_ip" ne seront pas retournées,
- les paires de clés publiques/privées associées ne peuvent être atteintes,

Edition : requêtes POST, PUT, DELETE

Exemple d’écriture d’un nouvel enregistrement en PHP avec cURL. Les données sont transmises au format application/x-www-form-urlencoded [2] :

  1. $data = array(
  2.     'client_id' => 'testtest',
  3.     'client_secret' => 'TheBigSecret',
  4.     'redirect_uri' => 'https://oa.dnc.global/web/?action=oauth',
  5.     'grant_types' => 'authorization_code',
  6.     'scope' => 'openid sli'
  7. );
  8.  
  9. $h = curl_init("https://oa.dnc.global/web/http.api/json/clients/");
  10. curl_setopt($h, CURLOPT_RETURNTRANSFER, true);
  11. curl_setopt($h, CURLOPT_TIMEOUT, 10);
  12. curl_setopt($h, CURLOPT_POST, true);
  13. curl_setopt($h, CURLOPT_HTTPHEADER, array('
  14.    Content-Type: application/x-www-form-urlencoded'),
  15.     'Accept: application/json'
  16. );  
  17. curl_setopt($h, CURLOPT_POSTFIELDS, http_build_query($data));
  18.  
  19. $res = curl_exec($h);
  20. ...

Télécharger

En HTML cela équivaudrait à :

  1. <?php
  2. $data = array(
  3.     'client_id' => 'testtest',
  4.     'client_secret' => 'TheBigSecret',
  5.     'redirect_uri' => 'https://oidc.dnc.global/web/?action=oauth',
  6.     'grant_types' => 'authorization_code',
  7.     'scope' => 'openid sli'
  8. );
  9. ?>
  10.  
  11. <form id="test_api_post" name="test_api_post" method="post" action="https://oidc.dnc.global/web/http.api/json/clients/">
  12. <input type="hidden" name="DBGSESSID" value="435347910947900005@127.0.0.1;d=1">
  13. <?php foreach ( $data as $name => $value ) { ?>
  14.     <input type="hidden" id="<?php echo $name;?>" name="<?php echo $name;?>" value="<?php echo $value;?>">
  15. <?php } ?>
  16.     <input type="submit">
  17. </form>

Télécharger

En cas de succès, la table clients est mise à jour et l’API retourne dans le corps de la réponse un array Json avec le client_id et l’id_client (index unique de la table clients) :

  1. {"
  2.    client_id":"testtest",
  3.     "id_client":43
  4. }

Télécharger

En cas de duplication, la réponse suivante est retournée :

  1. {
  2.   "collection": {
  3.     "version": "1.0",
  4.     "href": "https://oa.dnc.global/web/http.api/json/clients/",
  5.     "error": {
  6.       "title": "Erreur",
  7.       "code": 500
  8.     },
  9.     "errors": [
  10.       {
  11.         "title": "Erreur SQL 1062 Duplicate entry 'testtest' for key 'client_id'",
  12.         "code": 500
  13.       }
  14.     ]
  15.   }
  16. }

Télécharger

users (Utilisateurs finaux)

Le type users permet de nombreuses requêtes GET avec les formats collectionjson et json, notamment avec les paramètres offset et length. La requête suivante est pratique pour générer des tableaux paginés :

https://oa.dnc.global/web/http.api/collectionjson/users/?offset=100&length=10

Notez que la donnée sensible "password" ne sera pas retournée.

Enregistrement d’un utilisateur final sur le serveur OIDC

Le type users permet l’écriture (requêtes POST, PUT et DELETE).

Pour fonctionner, le contrôleur Authorize du serveur serveur OIDC n’a besoin que d’un username (ou d’un e-mail) et d’un mot de passe. Le contrôleur exploite également le contenu des autres champs fournis s’ils existent dans la table users et ne sont pas nuls.
En particulier, le champ scope peut être utilisé pour transmettre des autorisations propres à l’utilisateur.

Pour assurer la sécurité de l’authentification :
- lors de l’écriture, le secret client transmis en clair est enregistré sous forme de password_hash avec l’algorithme PASSWORD_BCRYPT.

auteurs (Administrateurs d’applications ou "superviseurs")

oidc_logs (événements)

Le type oidc_logs n’autorise que les requêtes suivantes, sous les formats json et collectionjson :

- Les événements étant triés par date décroissante, retourne length evenements depuis le rang 0 (donc les derniers événements) :

https://.../http.api/<format>/oidc_logs/?length=<nombre>

- Les événements étant triés par date décroissante, retourne length evenements depuis le rang offset :

https://.../http.api/<format>/oidc_logs/?offset=<rang>&length=<nombre>

- Les événements étant triés par date décroissante, retourne length événements autour du plus proche du temps indiqué par le timeserial ts :

https://.../http.api/<format>/oidc_logs/?ts=<timeserial>&length=<nombre>

- Retourne les évènements entre les timeserials tmin et tmax :

https://.../http.api/<format>/oidc_logs/?tmin=<timeserial>&tmax=<timeserial>

Notes :
- Il est interdit de lister l’ensemble de la collection.
- length est limité à 10000, sans génération d’erreur.


Sécurisation de l’accès à l’API

Deux configurations sont envisagées :
- Le serveur qui porte l’API est accessible uniquement par des applications de confiance à travers un canal sûr (par exemple au sein d’un réseau local d’entreprise bien isolé). Dans ce cas, la constante API_HTTP_AUTHENTICATE est fixée à ’false’ et des vérifications simples sont effectuées sur l’IP et/ou le domaine du client origine de la requête. Les constantes API_HTTP_CLIENT_IP et API_HTTP_CLIENT_HOST définissent les valeurs attendues.
- Le serveur se trouve sur un réseau public. Dans ce cas, la constante API_HTTP_AUTHENTICATE est fixée à ’true’ et l’application cliente doit s’authentifier avec le protocole OAuth 2.0. Pour ce faire, l’application cliente devra être enregistrée sur ce ce serveur OAuthSD avec les flux Authorization Code et Client Credentials. Notez que les contraintes définies par les constantes API_HTTP_CLIENT_IP et API_HTTP_CLIENT_HOST s’appliquent également.

Lorsqu’une application cliente veut accéder à l’API au nom d’un utilisateur final :
- l’application authentifie son utilisateur final avec le flux Authorization Code,
- si l’utilisateur final est authentifié, et seulement dans ce cas, l’application demande une autorisation d’accès en son nom propre avec le flux Client Credentials, puis passe le jeton d’accès obtenu dans l’appel à l’API,
- l’API vérifie le jeton d’accès par introspection.

En fait, l’API peut aussi bien valider un jeton d’accès qu’un jeton d’identification. L’application cliente peut donc s’authentifier directement avec le jeton d’identité obtenu avec le flux Authorization Code.

Lorsqu’une application cliente veut accéder à l’API en son nom propre :
- l’application demande une autorisation d’accès avec le flux Client Credentials, puis passe le jeton d’accès obtenu dans l’appel à l’API,
- l’API vérifie le jeton d’accès par introspection.

Le jeton peut être passé à l’API sous le nom ’token’ par les méthode POST ou GET, mais il est recommandé d’utiliser la méthode Auth Bearer.

Options

Les options suivantes sont définies dans le fichier collectionjsonoauthsd_options.php :

/* Cette API permet l’accès à la plupart des données manipulées par SPIP, les
types correspondant aux tables éponymes de la base de données. Cependant, autant
pour des raisons pratiques que de sécurité, les types servis sont limités à ceux
qui seront définis ici.
Si la chaine est ’’, tous les types seront autorisés.
Attention : le type est au singulier !*/
define(’API_HTTP_TYPES_AUTORISES’,’oidc_log,user,client,auteur,credential’) ;

/* S’agissant d’un serveur d’authentification, certaines données sont particulièrement
sensibles et doivent rester sanctuarisées.*/
define(’API_HTTP_CHAMPS_SENSIBLES’,’client_secret,client_ip,password’) ;

/* Si l’API doit être accessible autrement que par un client de confiance par
un canal sûr, il faut authentifier l’origine de la requête.
Cette constante peut aussi être fixée à false pendant le développement */
define(’API_HTTP_AUTHENTICATE’, false) ;

/* Si API_HTTP_AUTHENTICATE est fixé à true, l’authentification du client requiert
un jeton d’identité valide. Celui-ci contient la déclaration sub égale à l’id du
client (client_id). Si la constante suivante est non nulle, sub devra être égal à
la valeur indiquée. */
define(’API_HTTP_CLIENT_ID’, ’’) ;

/* Si API_HTTP_AUTHENTICATE a été fixé à false, il convient d’appliquer tout ou
partie des vérifications suivantes : */
define(’API_HTTP_CLIENT_IP’, ’’) ; // Vérifier que la requête vient de l’IP indiquée si non nulle
define(’API_HTTP_CLIENT_HOST’, ’’) ; // Vérifier que la requête vient du host indiqué si non nul

/* Si la requête ne définit pas le paramètre limit, les requêtes acceptant le
paramètre limit utiliseront la valeur suivante par défaut :*/
define (’API_DEFAULT_LENGTH’, 100) ;

/* Nombre maximum de lignes que peut retourner une requête (dans le cas où le paramètre
limit n’est pas requis, comme quand la requête n’accepte que les paramètres tmin et/ou tmax) :*/
define (’API_MAX_ITEMS_RETURNED’, 1000) ;

Utilisation de l’API par OAuthSD lui-même

OAuthSD utilise l’API notamment pour :
- La présentation des événements : charger les données de la table oidc_logs avec Ajax pour les présenter en scrolling continu. Voir le tableau de la page Statistiques.
- Permettre la supervision du serveur par une application extérieure.

API HTTP REST + TreeQL

  publié le par DnC

OAuthSD expose maintenant une deuxième API HTTP REST. Comme la première (qui reste disponible) cette API permet d’automatiser certaines tâches autour du serveur d’authentification. Une application d’administration (supervision) peut ainsi contrôler les données du serveur.
Cette nouvelle API s’appuie sur php-crud-api. Les objets sont manipulés sous des format scalaires ou json simples. Elle offre plus de possibilités de requêtes en suivant le format TreeQL.

Remarque : Cette API pourrait remplacer l’API HTTP REST à moyen terme.

Sécurisation de l’accès à l’API et transmission du rôle de l’utilisateur final

La sécurisation de l’accès à l’API HTTP REST + TreeQL est effectué à l’aide d’un jeton d’identité au format JWT émis par l’application cliente.

Ce jeton transmet le rôle de l’utilisateur au moyen de la déclaration ’scope’ prenant l’une des valeurs ’admin’, ’writer’, ’reader’ and ’none’. Pour cela (voir Définition des scopes OIDC et généralités sur leur utilisation par les applications) :
- l’application cliente doit utiliser OIDC et initialiser le flux d’autorisation avec code avec la demande d’autorisation (requested_scope) ’scope=privileges’,
- L’application cliente doit avoir été enregistrée avec la valeur ’privileges’ dans la liste de Scopes disponibles (Available scopes),
- une valeur parmi ’admin’, ’writer’, ’reader’ and ’none’ doit avoir été enregistrée dans la table users pour l’utilisateur final considéré.

Le jeton peut être passé dans l’URL (méthode GET), par POST ou par la méthode Authorization : Bearer.

Exemple d’appel avec la méthode GET :

https://oa.dnc.global/http.api/api.php/records/spip_users/1/?token=eyJ0eXAiOiJKV...

L’API valide le jeton JWT par introspection. OAuthSD garantit ainsi l’authenticité de l’application cliente. Voir : Vérification de l’origine de la requête reçue par un serveur de ressource.

En cas d’erreur d’authentification, l’API retourne un code HTTP 403 Forbidden et un corps vide.

Limitation de l’accès aux tables et aux champs

- seules les tables ’users’, ’clients’, ’scopes’, ’oidc_logs’ sont accessibles.

L’authentification de l’utilisateur final conduit à définir les rôles ’admin’, ’writer’, ’reader’ et ’none’. Le rôle ’admin’ peut effectuer l’ensemble des opérations.

Pour le rôle "writer" :
- dans la table ’public_keys’, la seule opération permise est la lecture de la clé clé publique.
- dans la table ’oauth_clients’, l’accès au champ password est interdit.
- dans la table ’oauth_users’, l’accès au champ client_secret est interdit.

Pour le rôle ’reader’ :
- les restriction d’accès sont les mêmes que le rôle ’writer’,
- seules les opérations ’read’ et ’list’ sont autorisées.

Le rôle ’none’ ne peut que lire la table ’oidc_logs’.

Opérations CRUD + List : Référence de l’API

Voyez également :
- https://oa.dnc.global/http.api/spec/swagger/static/
- https://editor.swagger.io/?url=https://oa.dnc.global/http.api/api.php/openapi

Sélections avancées

Sur les opérations de liste, vous pouvez appliquer des filtres et des jointures.

Les exemples suivants supposent la table suivante :

posts
id
titre
content message

Filtres

Les filtres fournissent une fonctionnalité de recherche sur les appels de liste, en utilisant le paramètre "filter". Vous devez spécifier le nom de la colonne, une virgule, le type de correspondance, une autre virgule et la valeur que vous souhaitez filtrer.

Types de match supportés :

"cs" : contient une chaîne (la chaîne contient une valeur)
"sw" : commence par (chaîne commence par valeur)
"ew" : se termine par (chaîne se termine par valeur)
"eq" : égal (la chaîne ou le nombre correspond exactement)
"lt" : inférieur à (nombre inférieur à la valeur)
"le" : inférieur ou égal (le nombre est inférieur ou égal à la valeur)
"ge" : supérieur ou égal (le nombre est supérieur ou égal à la valeur)
"gt" : supérieur à (nombre supérieur à la valeur)
"bt" : entre (le nombre est entre deux valeurs séparées par une virgule)
"in" : in (le nombre ou la chaîne est dans une liste de valeurs séparées par des virgules)
"is" : est null (le champ contient la valeur "NULL")

Vous pouvez annuler tous les filtres en ajoutant un caractère "n", afin que "eq" devienne "neq". Exemples d’utilisation du filtre :

GET / records / categories? Filter = nom, eq, Internet
GET / records / categories? Filter = nom, sw, Inter
GET / records / categories? Filter = id, le, 1
GET / records / categories? Filter = id, ngt, 2
GET / records / categories? Filter = id, bt, 1,1

Filtres multiples

Les filtres peuvent être appliqués en répétant le paramètre "filter" dans l’URL. Par exemple l’URL suivante :

GET / records / categories ? Filter = id, gt, 1 & filter = id, lt, 3

demandera toutes les catégories "où id> 1 et id <3". Si vous vouliez "où id = 2 ou id = 4", vous devriez écrire :

GET / enregistrements / catégories ? Filter1 = id, eq, 2 & filter2 = id, eq, 4

Comme vous le voyez, nous avons ajouté un numéro au paramètre "filter" pour indiquer que "OR" au lieu de "AND" doit être appliqué. Notez que vous pouvez également répéter "filter1" et créer un "ET" dans un "OU". Comme vous pouvez également aller plus loin en ajoutant une lettre (a-f), vous pouvez créer presque n’importe quel arbre de conditions relativement complexe.

Notes :
- Vous ne pouvez filtrer que sur la table demandée (pas sur la table incluse) et les filtres ne sont appliqués qu’aux appels de liste.

Sélection de colonne

Par défaut, toutes les colonnes sont sélectionnées. Avec le paramètre "include", vous pouvez sélectionner des colonnes spécifiques. Vous pouvez utiliser un point pour séparer le nom de la table du nom de la colonne. Plusieurs colonnes doivent être séparées par des virgules. Un astérisque ("*") peut être utilisé comme caractère générique pour indiquer "toutes les colonnes". Semblable à "include", vous pouvez utiliser le paramètre "exclude" pour supprimer certaines colonnes :

GET / enregistrements / catégories / 1 ? Include = nom
GET /records/categories/1 ?include=categories.name
GET /records/categories/1 ?exclude=categories.id

Sortie :

   {
       "nom": "Internet"
   }

Notes :
- Les colonnes utilisées pour inclure des entités associées sont automatiquement ajoutées et ne peuvent pas être omises de la sortie.

Tri

Avec le paramètre "order", vous pouvez trier. Par défaut, le tri s’effectue par ordre croissant, mais en spécifiant "desc", cela peut être inversé :

GET / records / categories ? Order = nom, desc
GET / enregistrements / catégories ? Order = id, desc & order = name

Sortie :

   {
       "records": [
           {
               "id": 3
               "name": "développement Web"
           },
           {
               "id": 1
               "nom": "Internet"
           }
       ]
   }

Notes :
- Vous pouvez trier sur plusieurs champs en utilisant plusieurs paramètres "ordre". Vous ne pouvez pas commander sur des colonnes "jointes".

Taille limite

Le paramètre "size" limite le nombre d’enregistrements renvoyés. Ceci peut être utilisé pour les N premières listes avec le paramètre "order" (utilisez l’ordre décroissant).

GET / records / categories ? Order = id, desc & size = 1

Sortie :

   {
       "records": [
           {
               "id": 3
               "name": "développement Web"
           }
       ]
   }

Notes :
- Si vous souhaitez également connaître le nombre total d’enregistrements, vous pouvez utiliser le paramètre "page".

Pagination

Le paramètre "page" contient la page demandée. La taille de page par défaut est 20, mais peut être ajustée (par exemple à 50).

GET / records / categories ? Order = id & page = 1
GET / records / categories ? Order = id & page = 1,50

Sortie :

   {
       "records": [
           {
               "id": 1
               "nom": "Internet"
           },
           {
               "id": 3
               "name": "développement Web"
           }
       ],
       "résultats": 2
   }

Notes :
- les pages non commandées ne pouvant pas être paginées, elles seront classées par clé primaire.

Jointures

Supposons que vous ayez une table des publications qui comporte des commentaires (formulés par les utilisateurs) et que les publications puissent avoir des balises. Les exemples suivants supposent le jeu de tables suivant :

posts commentaires utilisateurs post_tags tags
id id id id id
titre post_id nom d’utilisateur post_id nom
content user_id phone tag_id
message créé

Lorsque vous souhaitez répertorier les publications avec leurs commentaires, les utilisateurs et les balises, vous pouvez demander deux chemins "arborescents" :

messages -> commentaires -> utilisateurs
posts -> post_tags -> tags
Ces chemins ont la même racine et cette demande peut être écrite au format URL comme suit :

GET / records / posts ? Join = commentaires, utilisateurs & tags = join

Ici, vous êtes autorisé à laisser de côté la table intermédiaire qui lie les publications aux balises. Dans cet exemple, les trois types de relation de table (hasMany, belongsTo et hasAndBelongsToMany) sont en jeu :

"post" a beaucoup de "commentaires"
"commentaire" appartient à "utilisateur"
"post" a et appartient à beaucoup de "tags"

Cela peut entraîner les données JSON suivantes :

{
   "records": [
       {
           "id": 1,
           "title": "Bonjour tout le monde!",
           "content": "Bienvenue dans le premier message.",
           "created": "2018-03-05T20: 12: 56Z",
           "commentaires": [
               {
                   id: 1,
                   post_id: 1,
                   identifiant d'utilisateur: {
                       id: 1,
                       nom d'utilisateur: "mevdschee",
                       téléphone: null,
                   },
                   message: "Salut!"
               },
               {
                   id: 2,
                   post_id: 1,
                   identifiant d'utilisateur: {
                       id: 1,
                       nom d'utilisateur: "mevdschee",
                       téléphone: null,
                   },
                   message: "Salut encore!"
               }
           ],
           "Mots clés": []
       },
       {
           "id": 2,
           "title": "Le noir est le nouveau rouge",
           "content": "Ceci est le deuxième message.",
           "created": "2018-03-06T21: 34: 01Z",
           "commentaires": [],
           "Mots clés": [
               {
                   id: 1,
                   message: "drôle"
               },
               {
                   id: 2,
                   message: "informatif"
               }
           ]
       }
   ]
}

Vous voyez que les relations "belongsTo" sont détectées et la valeur de la clé étrangère est remplacée par l’objet référencé. Dans le cas de "hasMany" et "hasAndBelongsToMany", le nom de la table est utilisé comme nouvelle propriété de l’objet.

Opérations par lots

Lorsque vous souhaitez créer, lire, mettre à jour ou supprimer, vous pouvez spécifier plusieurs valeurs de clé primaire dans l’URL. Vous devez également envoyer un tableau au lieu d’un objet dans le corps de la demande pour créer et mettre à jour.

Pour lire un enregistrement de cette table, la demande peut être écrite au format URL sous la forme suivante :

GET / records / posts / 1,2

Le résultat peut être :

[
       {
           "id": 1,
           "title": "Bonjour tout le monde!",
           "content": "Bienvenue dans le premier message.",
           "created": "2018-03-05T20: 12: 56Z"
       },
       {
           "id": 2,
           "title": "Le noir est le nouveau rouge",
           "content": "Ceci est le deuxième message.",
           "created": "2018-03-06T21: 34: 01Z"
       }
]

De même, lorsque vous souhaitez effectuer une mise à jour par lot, la demande au format URL est écrite comme suit :

PUT / records / posts / 1,2

Où "1" et "2" sont les valeurs des clés primaires des enregistrements que vous souhaitez mettre à jour. Le corps devrait contenir le même nombre d’objets qu’il y a de clés primaires dans l’URL :

[
   {
       "titre": "Titre ajusté pour ID 1"
   },
   {
       "titre": "Titre ajusté pour ID 2"
   }
]

Ceci ajuste les titres des messages. Et les valeurs de retour sont le nombre de lignes définies :

1,1

Ce qui signifie qu’il y avait deux opérations de mise à jour et que chacune d’entre elles avait défini une ligne. Les opérations en mode batch utilisent des transactions de base de données, de sorte qu’elles réussissent ou échouent (les transactions réussies sont renvoyées).

Stylage des formulaires d’identification

  publié le par DnC

OAuthSD offre deux moyens d’apdater les formulaires à la charte graphique d’une organisation :
- my.css féfinit les styles propres à une organisation, qui s’appliqueront à tous les clients inscrits sur le serveur,
- le champ css de la table Clients sera éventuellement utilisé pour attribuer un stylage particulier à une application.

Structure générale des formulaires

Le corps des formulaires présente la structure HTML suivante :

  1. ...
  2. <div id="page" class="(le nom de la méthode)">    
  3.        <div id="top"></div>
  4.         <div id="container">  
  5.             <h3 class="head-title"> ... </h3>
  6.             ...
  7.             <div class="error"> ... </div>
  8.             ...
  9.         </div>
  10.     <div id="bottom">
  11.         ...
  12.     </div>
  13. </div>

Télécharger

Adaptation de la charte graphique

Styles par défaut

Par défaut, les styles des formulaires d’identification sont définis dans la section head de chacun d’eux.

Fichier my.css

S’il existe un fichier /my.css à la racine du serveur, celui-ci est adopté comme feuille de style.

Ce fichier pourra être utilisé pour insérer un logo de l’organisation. Le champ #top est sans doute bien adapté à recevoir une image en background.

Champ css de la table Clients

Qu’il s’agisse de la feuille de style ou du défaut, les styles peuvent être complétés ou surchargés par le contenu du champ css de la table clients. Dans l’exemple ci-dessous, la variable $thecss contient les données de ce champ.

Ces styles intervenant en final, ils l’emportent sur les précédents.

Exemple

Voici par exemple les définitions de styles du formulaire de login :

PHP

  1. // Styles
  2.  
  3. $thecss = ( empty($data['css'])? '' : htmlspecialchars($data['css']) );
  4.  
  5. if ( file_exists('my.css') ) { //[dnc37]
  6.     $style = '<link rel="stylesheet" type="text/css" href="my.css">" .';
  7.     if ( !empty($thecss) ) $style .= $thecss;
  8. } else {
  9.     $style = '
  10.    <style>
  11.    body {font-family: "Century Gothic", Helvetica, Arial, sans-serif !important;}
  12.    #page {margin-left: auto; margin-right: auto; max-width: 360px; padding: 1.5em; border: solid 1px grey; border-radius: 10px; box-shadow: 10px 5px 5px silver;}
  13.    .head-title {text-align: center; background-color: gray; color: white; padding: 0.5em;}
  14.    .error {text_align: center; color : red; background-color : white; padding: 6px;}
  15.    .bouton {margin:15px; cursor:pointer;}
  16.    .tfacode {text-align: center;}
  17.    #champ_login {box-shadow: 10px 5px 5px silver; margin-bottom: 10px;}
  18.    #champ_password {border: none;};
  19.    #btn_reset {float: left;}
  20.    #btn_submit {float: right;}
  21.    #submit {width:100px; font-size: 1.1em;}
  22.    #nologin {clear: both; margin-bottom: 0.5em;}
  23.    #ghostkeys {height: 120px; text-align: center;}
  24.    #ghostkeys > img {box-shadow: 10px 5px 5px silver;}
  25.    #bottom {color : grey; font-size: .8em;}
  26.    #bottom a {color : grey;}
  27.    ' . $thecss . '
  28.    </style>
  29.    ';    
  30.     }

Télécharger

Formulaire d’identification avec GhostKeys