Für diejenigen, die von Google kommen: Sie sollten die Nonces wahrscheinlich nicht von der REST-API erhalten , es sei denn, Sie wissen wirklich , was Sie tun. Die Cookie-basierte Authentifizierung mit der REST-API ist nur für Plugins und Themes gedacht . Für eine Anwendung mit nur einer Seite sollten Sie wahrscheinlich OAuth verwenden .
Diese Frage besteht, weil in der Dokumentation nicht klar ist, wie Sie sich beim Erstellen von Apps für einzelne Seiten tatsächlich authentifizieren sollten, JWTs nicht wirklich für Web-Apps geeignet sind und OAuth schwieriger zu implementieren ist als die Cookie-basierte Authentifizierung.
Das Handbuch enthält ein Beispiel dafür, wie der Backbone-JavaScript-Client mit Nonces umgeht. Wenn ich dem Beispiel folge, erhalte ich eine Nonce, die von den integrierten Endpunkten wie / wp / v2 / posts akzeptiert wird.
\wp_localize_script("client-js", "theme", [
'nonce' => wp_create_nonce('wp_rest'),
'user' => get_current_user_id(),
]);
Die Verwendung von Backbone kommt jedoch nicht in Frage, ebenso wie Themen. Deshalb habe ich das folgende Plugin geschrieben:
<?php
/*
Plugin Name: Nonce Endpoint
*/
add_action('rest_api_init', function () {
$user = get_current_user_id();
register_rest_route('nonce/v1', 'get', [
'methods' => 'GET',
'callback' => function () use ($user) {
return [
'nonce' => wp_create_nonce('wp_rest'),
'user' => $user,
];
},
]);
register_rest_route('nonce/v1', 'verify', [
'methods' => 'GET',
'callback' => function () use ($user) {
$nonce = !empty($_GET['nonce']) ? $_GET['nonce'] : false;
return [
'valid' => (bool) wp_verify_nonce($nonce, 'wp_rest'),
'user' => $user,
];
},
]);
});
Ich habe ein bisschen an der JavaScript-Konsole herumgebastelt und folgendes geschrieben:
var main = async () => { // var because it can be redefined
const nonceReq = await fetch('/wp-json/nonce/v1/get', { credentials: 'include' })
const nonceResp = await nonceReq.json()
const nonceValidReq = await fetch(`/wp-json/nonce/v1/verify?nonce=${nonceResp.nonce}`, { credentials: 'include' })
const nonceValidResp = await nonceValidReq.json()
const addPost = (nonce) => fetch('/wp-json/wp/v2/posts', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({
title: `Test ${Date.now()}`,
content: 'Test',
}),
headers: {
'X-WP-Nonce': nonce,
'content-type': 'application/json'
},
}).then(r => r.json()).then(console.log)
console.log(nonceResp.nonce, nonceResp.user, nonceValidResp)
console.log(theme.nonce, theme.user)
addPost(nonceResp.nonce)
addPost(theme.nonce)
}
main()
Das erwartete Ergebnis sind zwei neue Beiträge, aber ich bekomme Cookie nonce is invalid
vom ersten und der zweite erstellt den Beitrag erfolgreich. Das liegt wahrscheinlich daran, dass die Nonces unterschiedlich sind, aber warum? Ich bin in beiden Anfragen als derselbe Benutzer angemeldet.
Wenn mein Ansatz falsch ist, wie soll ich die Nonce bekommen?
Bearbeiten :
Ich habe versucht, ohne viel Glück mit Globals zu spielen . Ich habe ein bisschen mehr Glück mit der Aktion wp_loaded:
<?php
/*
Plugin Name: Nonce Endpoint
*/
$nonce = 'invalid';
add_action('wp_loaded', function () {
global $nonce;
$nonce = wp_create_nonce('wp_rest');
});
add_action('rest_api_init', function () {
$user = get_current_user_id();
register_rest_route('nonce/v1', 'get', [
'methods' => 'GET',
'callback' => function () use ($user) {
return [
'nonce' => $GLOBALS['nonce'],
'user' => $user,
];
},
]);
register_rest_route('nonce/v1', 'verify', [
'methods' => 'GET',
'callback' => function () use ($user) {
$nonce = !empty($_GET['nonce']) ? $_GET['nonce'] : false;
error_log("verify $nonce $user");
return [
'valid' => (bool) wp_verify_nonce($nonce, 'wp_rest'),
'user' => $user,
];
},
]);
});
Wenn ich jetzt das obige JavaScript ausführe, werden zwei Beiträge erstellt, aber der Endpunkt zur Überprüfung schlägt fehl!
Ich ging zum Debuggen von wp_verify_nonce:
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce;
$user = wp_get_current_user();
$uid = (int) $user->ID; // This is 0, even though the verify endpoint says I'm logged in as user 2!
Ich habe etwas Protokollierung hinzugefügt
// Nonce generated 0-12 hours ago
$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
error_log("expected 1 $expected received $nonce uid $uid action $action");
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
// Nonce generated 12-24 hours ago
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
error_log("expected 2 $expected received $nonce uid $uid action $action");
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
und der JavaScript-Code führt nun zu den folgenden Einträgen. Wie Sie sehen können, ist uid beim Aufruf des Verifizierungsendpunkts 0.
[01-Mar-2018 11:41:57 UTC] verify 716087f772 2
[01-Mar-2018 11:41:57 UTC] expected 1 b35fa18521 received 716087f772 uid 0 action wp_rest
[01-Mar-2018 11:41:57 UTC] expected 2 dd35d95cbd received 716087f772 uid 0 action wp_rest
[01-Mar-2018 11:41:58 UTC] expected 1 716087f772 received 716087f772 uid 2 action wp_rest
[01-Mar-2018 11:41:58 UTC] expected 1 716087f772 received 716087f772 uid 2 action wp_rest