A l’aide de l’API REST WordPress, comment créer un Endpoint accessible à partir d’une URL qui soit protégé par une authentification.
Je décris ici toutes les étapes (sans entrer dans les détails qui eux le sont dans mes autres articles accessibles à partir du menu)
Pour ce résumé, mon site distant est http://votre-site-distant auquel j’accède grâce à une application Python. (si vous ne connaissez ni WordPress, ni Python, ni PHP, ni comment écrire un Plugin WP, ni ce qu’est oAuth cet article n’est pas pour vous – je sais c’est dur !)
J’utilise aussi un site local (bs4) pour faciliter la compréhension des étapes (mais ce n’et pas utile dans mon cas car l’accès est via une application Python)
Ma référence principale pour mes articles est : https://blog.datafeedr.com/using-oauth-1-0-wordpress-api-custom-endpoints/ (datafeedr)
1 – vérification que l’API REST est activée sur mon site distant
(voir mon § Introduction)
http://votre-site-distant/wp-json
Comme on peut le constater, quand c’est le cas :
« namespaces« :[
- « oembed\/1.0 »,
- « wc\/v1 »,
- « wp\/v2 »
],
wp\/v2 prouve l’existence de l’API REST. Ma version de WordPress est la 4.7.2–fr_FR.
L’API Woocommerce est aussi installée mais elle n’est pas utile ici.
Si vous n’avez pas wp/v2 c’est que votre version WP est inférieure à la 4.7.1. Dans votre cas il faut installer l’API.
2 – Installation du plugin WordPress REST API – OAuth 1.0a Server
Lire : Ajouter ses propres Endpoints – #3
Si le plugin n’est pas installé, et que l’API REST WP l’est, alors l’appel de http://votre-site-distant/wp-json devrait retourner (sous le namespaces) :
"authentication":[],
Comme il nous faut une authentification, installez et activez WordPress REST API – OAuth 1.0a Server
Suite à quoi, vous aurez désormais (lors de l’appel) de http://votre-site-distant/wp-json
« authentication« :{
- « oauth1« :{
- « request« :« http:\/\/votre-site-distant/\/oauth1\/request »,
- « authorize« :« http:\/\/votre-site-distant/\/oauth1\/authorize »,
- « access« :« http:\/\/votre-site-distant/\/oauth1\/access »,
- « version« :« 0.1 »
}
},
3 – Création d’un plugin de test sur le site local
J’ai créé le plugin jb_test_bs4 et je l’ai activé (test_api_connection.php)
Il définit le shortcode [test_api_connection]
<!--?php /** * Test connection to API without any authentication headers. */ add_shortcode( 'test_api_connection', 'my_test_api_connection' ); function my_test_api_connection() { $url = 'http://votre-site-distant/wp-json'; $response = wp_remote_get( $url ); $api_response = json_decode( wp_remote_retrieve_body( $response ), true ); return print_r( $api_response, true ) ; }
J’ai créé la page de test http://localhost:8888/bs4/test-1/. Elle contient :
test_api_connection
[test_api_connection]
Lorsque je lance la page http://localhost:8888/bs4/test-1/ j’obtiens bien la preuve de l’installation de l’API REST, de l’authentification, et la liste des endpoints [request], [authorize], [access] que nous allons utiliser pour obtenir les clés nécessaires à l’authentification.
[name] => xxx [description] => xxx [url] => http://votre-site-distant [home] => http://votre-site-distant [namespaces] => Array ( [0] => oembed/1.0 [1] => wc/v1 [2] => wp/v2 ) [authentication] => Array ( [oauth1] => Array ( [request] => http://votre-site-distant/oauth1/request [authorize] => http://votre-site-distant/oauth1/authorize [access] => http://votre-site-distant/oauth1/access [version] => 0.1 ) )
L’appel à http://votre-site-distant/oauth1/request retournera pour l’instant : No OAuth parameters supplied
4 – Création de l’application Client Api
Dans le panneau d’administration WP de vostre site distant, sous Utilisateurs, il y a un menu Applications. Nous allons en créer une (remplissez avec les noms que vous voulez, ça n’a pas d’importance)
Consumer Name : Client Api Connection
Description : Client Api Connection sur votre-site-distant
Callback : http://votre-site-distant/success
Après validation de votre application, vous obtiendrez 2 clés (à conserver) :
Client Key : Gacxxxgt1
Client Secret 0O5xxxKCw
5 – Obtention des clés avec Postman
Nous allons utiliser Postman pour la suite. Postman est une extension Chrome qui permet d’appeler et tester une API Web.
Suivre les étapes suivantes :
A – http://votre-site-distant/oauth1/request
GET http://votre-site-distant/oauth1/request (vous pouvez aussi faire un POST – voir mes autres articles)
Sélectionnez le type d’authentification oAuth1. Remplissez le Consumer Key avec votre Client Key et le Consumer Secret avec votre Client Secret.
Faites un Update request (ce qui mettra à jour le Timestamp et le Nonce)
Afin d’obtenir des tokens d’authentification provisoire.
Votre requête doit être du type :
et vous obtiendrez une réponse du type :
oauth_token=E9kjxxxElp&oauth_token_secret=Vve8xxxlF0&oauth_callback_confirmed=true
B – http://www.votre-site-distant/oauth1/authorize
Connectez-vous à votre site distant, avec un nom d’utilisateur (qui n’est pas l’administrateur d’origine) et qui a des droits suffisants.
Sélectionnez le type d’authentification oAuth1. Remplissez le Consumer Key avec votre Client Key et le Consumer Secret avec votre Client Secret, le Token avec celui obtenu dans l’étape précédent, et idem pour le Token Secret.
Puis Update Request et Send.
Puis reprenez la requête http://www.votre-site-distant/oauth1/authorize?oauth_consumer_key=Gacxxxgt1&oauth_token=E9kjxxxElp&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1488274985&oauth_nonce=l91xxx&oauth_version=1.0&oauth_signature=a3UZxxxRhNs=
et lancez là dans votre navigateur (celui où vous êtes déjà connecté au site distant)
Vous obtiendrez (visible avec Preview) quelque chose du type :
Cliquez sur Authorize et vous obtiendrez :
Your verification token is BxgxxxtHpl
C – http://www.votre-site-distant/oauth1/access?oauth_verifier=BxgxxxtHpl
Dans Postman, nouvelle requête :
Cette fois je fais un Post (mais le GET est aussi possible) – Add param to headers
POST http://www.votre-site-distant/oauth1/access?oauth_verifier=BxgxxxtHpl
Les autres paramètres sont ceux de l’étape précédent.
Cette fois on reçoit les tokens définitifs.
oauth_token=tLgmxxxx2y&oauth_token_secret=dzrxxxyVa
Vous pouvez vous débarrasser des anciens.
D – Vérification que l’application est autorisée
Dans le panneau WP, vérifiez que sous utilisateur, vous avez (sour le profil) : Authorized Applications : Client Api Connection
Création de votre propre endpoint
Arrivé à cette étape, nous disposons des clés d’authentification pour accéder à l’API REST.
Nous allons désormais créer notre propre URL de destination.
A – myapiplugin sur site distant
Créez, installez et activez myapiplugin sur votre-site-distant. C’est un plugin qui ne fait rien d’autre que d’afficher qu’il existe (après avoir vérifié les autorisations requises).
B – modification des shortcodes
Modifiez aussi vos shortcodes de la façon suivante (ajout de OAuth_Authorization_Header et test_api_oauth_connection (en n’oubliant pas de mettre vos propres clés dans le fichier))
C – Modification de la page de test (en local)
test_api_connection
[test_api_connection]
test_api_oauth_connection
[test_api_oauth_connection]
D – Appel de la page : http://localhost:8888/bs4/test-1/
et j’obtiens :
test_api_connection
Array
(
=> rest_forbidden
[message] => Désolé, vous n’avez pas l’autorisation de faire cela.
[data] => Array
(
[status] => 403
)
)
test_api_oauth_connection
Array
(
[greeting] => Hello!
[message] => You have successfully called my custom endpoint.
)
Ce qui est exactement ce que je voulais !
Il suffit désormais de remplacer myapiplugin par le plugin que je souhaite et d'appeler l'URL dans mon logiciel Python.
6 - Avec Woocommerce
J'ai ensuite fait un test sur un site qui a Woocommerce installé. Et là ça ne marche pas.
J'ai d'abord commencé sans Woocommerce. C'était OK. J'ai installé Woocommerce et ça ne marchait plus. J'ai désinstallé Woocommerce et ça ne marchait pas de nouveau.
Après quelques heures... j'ai trouvé la solution (dont j'ai déjà parlé) : .htaccess
J'ai changé le .htaccess à la racine - de la façon suivante :
(voir l'article https://github.com/WP-API/Basic-Auth/issues/35)
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
J'ai réinstallé Woocommerce, et là c'est encore bon.
J'ai mis les droits 444 à .htaccess pour qu'il ne soit pas modifié par WP.
Il y aussi la possibilité d'utiliser : le plugin https://wordpress.org/plugins/wp-htaccess-control/ comme proposé ici https://github.com/WP-API/Basic-Auth/issues/35 (mais je ne l'ai pas testé)
Paramètres
Je pensais que ce § serait straightforward ! mais ça n'a pas été le cas.
J'ai modifié mon shortcode pour passer un paramètre :
http://www.votre-site-distant/wp-json/myapiplugin/v2/greeting/345
A - Phase 1
l'appel de mon shortcode (site local) est :
function my_test_api_oauth_connection() {
$url = 'http://www.votre-site-distant/wp-json/myapiplugin/v2/greeting/345';
et mon plugin est modifié de la façon suivante pour le test :
add_action( 'rest_api_init', 'myapiplugin_registered_routes' );
function myapiplugin_registered_routes() {
register_rest_route( 'myapiplugin/v2', 'greeting/(?P\d+)', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'myapiplugin_serve_route',
'permission_callback' => 'myapiplugin_permission_callback',
) );
}
function myapiplugin_serve_route( WP_REST_Request $request ) {
$response = array(
'greeting' => 'Hello!',
'message' => 'You have successfully called my custom endpoint.',
'parametre' => $request['id']
);
return $response;
}
Lire aussi http://www.regular-expressions.info/named.html sur les expressions régulières.
A - Phase 2
Ici je passe un passe un paramètre, qui est accepté par le Endpoint et j'exécute une requête MySQL dans le plugin.
Le code de mon plugin :
add_action( 'rest_api_init', 'myapiplugin_registered_routes' );
function myapiplugin_registered_routes() {
register_rest_route( 'myapiplugin/v2', 'greeting/(?P\d+)/(?P\d+)', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'myapiplugin_serve_route',
'permission_callback' => 'myapiplugin_permission_callback'
) );
}
function myapiplugin_permission_callback() {
return current_user_can( 'update_core' );
}function myapiplugin_serve_route( WP_REST_Request $request ) {
global $wpdb;
$users=$wpdb->get_results("SELECT * FROM wp_users");
$response = array(
'greeting' => 'Hello!',
'message' => 'You have successfully called my custom endpoint.',
'id' => $request['id'],
'nom' => $request['nom'],
'post' => $users
);
return $response;
}
Le code de mes shortcodes (en local)
add_shortcode( 'test_api_connection', 'my_test_api_connection' );
function my_test_api_connection() {
$url = 'http://mon-site-distant/wp-json/myapiplugin/v2/greeting/79/567';
$response = wp_remote_get( $url );
$api_response = json_decode( wp_remote_retrieve_body( $response ), true );return '
' . print_r( $api_response, true ) . '';
}add_shortcode( 'test_api_oauth_connection', 'my_test_api_oauth_connection' );
function my_test_api_oauth_connection() {
$url = 'http://mon-site-distant.com/wp-json/myapiplugin/v2/greeting/79/567';
$method = 'GET';$keys = array(
'oauth_consumer_key' => 'ZINxxxTM',
'oauth_consumer_secret' => 'G4Oxxx9k1D',
'oauth_token' => 'XTZxxxNJm',
'oauth_token_secret' => 'qswoxxxeOT',
);$oauth = new OAuth_Authorization_Header( $keys, $url, $method );
$header = $oauth->get_header();
$args = array( 'headers' => array( 'Authorization' => $header ) );
$response = wp_remote_get( $url, $args );
$api_response = json_decode( wp_remote_retrieve_body( $response ), true );
return '' . print_r( $api_response, true ) . '';
}
Le résultat (attendu - enfin !)
test_api_connection
Array ( => rest_forbidden [message] => Désolé, vous n’avez pas l’autorisation de faire cela. [data] => Array ( [status] => 403 ) )
test_api_oauth_connection
Array ( [greeting] => Hello! [message] => You have successfully called my custom endpoint. [id] => 79 [nom] => 567 [post] => Array ( [0] => Array ( [ID] => 1 [user_login] => jbs [user_pass] => $P$xxxhin1 [user_nicename] => jbr [user_email] => jxx@xxx.com [user_url] => [user_registered] => 2015-02-27 09:18:55 [user_activation_key] => [user_status] => 0 [display_name] => jbs ) [1] => Array ( [ID] => 2 [user_login] => bidon [user_pass] => $P$xxxXTr1 [user_nicename] => bidon [user_email] => j@yahoo.com [user_url] => [user_registered] => 2017-02-16 14:09:56 [user_activation_key] => 1487xxxvu1 [user_status] => 0 [display_name] => Bi Don ) ) )
Et en python
ça y est. Enfin au but !
Pour python, j'utilise le module décrit ici : L’authentification WP OAUTH REST
Le code pour accéder à mon Endpoint sécurisé :
>>> import requests
>>> from requests_oauthlib import OAuth1
>>> url = 'http://mon-site-distant.com/wp-json/myapiplugin/v2/greeting/79/567'
>>>
>>> oauth_consumer_key = 'ZINxxxITM'
>>> oauth_consumer_secret = 'G4OIxxx9k1D'
>>> oauth_token = 'XTZxxx5NJm'
>>> oauth_token_secret = 'qswoxxxeOT'
>>>
>>> auth = OAuth1(oauth_consumer_key, oauth_consumer_secret,oauth_token, oauth_token_secret)
>>> requests.get(url, auth=auth)
>>> print(response.text)
et j'obtiens :
{"greeting":"Hello!","message":"You have successfully called my custom endpoint.","id":"79","nom":"567","post":[{"ID":"1","user_login":"jbs","user_pass":"$P$xxxhin1","user_nicename":"jboscher","user_email":"j@xxx.com","user_url":"","user_registered":"2015-02-27 09:18:55","user_activation_key":"","user_status":"0","display_name":"jbs"},
{"ID":"2","user_login":"bidon","user_pass":"$P$xxxTr1","user_nicename":"bidon","user_email":"j@yahoo.com","user_url":"","user_registered":"2017-02-16 14:09:56","user_activation_key":"1487254197:$P$BboRFIpdkMhlPqAF.mD5J0JS8pX.vu1","user_status":"0","display_name":"Bi Don"}]}