Dla tych, którzy przybywają z Google: Prawdopodobnie nie powinieneś otrzymywać noncesów z interfejsu API REST , chyba że naprawdę wiesz, co robisz. Uwierzytelnianie oparte na ciasteczka z API reszta jest tylko przeznaczona dla wtyczek i tematów. W przypadku aplikacji na jedną stronę prawdopodobnie powinieneś użyć OAuth .
To pytanie istnieje, ponieważ dokumentacja nie jest / nie była jasna, w jaki sposób należy uwierzytelniać podczas tworzenia aplikacji jednostronicowych, JWT tak naprawdę nie nadają się do aplikacji internetowych, a OAuth jest trudniejszy do wdrożenia niż uwierzytelnianie oparte na plikach cookie.
Podręcznik zawiera przykład, w jaki sposób klient JavaScript Backbone obsługuje jednostki nonces, a jeśli podążę za tym przykładem, otrzymam komunikat, który akceptuje wbudowane punkty końcowe, takie jak / wp / v2 / posts.
\wp_localize_script("client-js", "theme", [
'nonce' => wp_create_nonce('wp_rest'),
'user' => get_current_user_id(),
]);
Jednak użycie Backbone jest wykluczone, podobnie jak motywy, więc napisałem następującą wtyczkę:
<?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,
];
},
]);
});
Trochę majstrowałem w konsoli JavaScript i napisałem:
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()
Oczekiwanym rezultatem są dwa nowe posty, ale otrzymuję Cookie nonce is invalid
od pierwszego, a drugi z powodzeniem tworzy post. Prawdopodobnie dlatego, że jednostki są różne, ale dlaczego? Jestem zalogowany jako ten sam użytkownik w obu żądaniach.
Jeśli moje podejście jest błędne, jak powinienem otrzymać ten nonce?
Edytuj :
Próbowałem zadzierać z globalnymi bez większego szczęścia . Masz trochę więcej szczęścia, korzystając z akcji 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,
];
},
]);
});
Teraz, gdy uruchamiam JavaScript powyżej, tworzone są dwa posty, ale weryfikacja punktu końcowego kończy się niepowodzeniem!
Poszedłem do debugowania 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!
Dodałem trochę logowania
// 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;
}
a kod JavaScript skutkuje teraz następującymi wpisami. Jak widać, po wywołaniu punktu końcowego weryfikacji uid wynosi 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
źródło
$_GET['nonce']
, ale nagłówek lub$_GET['_wpnonce']
parametr nonce . Poprawny?Chociaż to rozwiązanie działa, nie jest zalecane . OAuth jest preferowanym wyborem.
Myślę, że rozumiem.
Myślę , że wp_verify_nonce jest uszkodzony, ponieważ wp_get_current_user nie może uzyskać odpowiedniego obiektu użytkownika.Tak nie jest, jak ilustruje Otto.
Na szczęście ma filtr:
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
Za pomocą tego filtra udało mi się napisać, a kod JavaScript działa tak, jak powinien:
Jeśli zauważysz problem związany z poprawką, daj mi krzyk, teraz nie widzę w tym nic złego oprócz globali.
źródło
Patrząc na cały ten kod, wydaje się, że twoim problemem jest użycie zamknięć. Na
init
etapie należy jedynie ustawiać haki i nie oceniać danych, ponieważ nie wszystkie rdzenie zakończyły ładowanie i zostały zainicjowane.W
$user
jest związany wcześnie, aby być stosowany w zamknięciu, ale nikt nie obiecuje wam, że ciasteczka były już obsługiwane, a użytkownik został uwierzytelniony na ich podstawie. Lepszy będzie kodJak zawsze z dowolnym hakiem w Wordpress, użyj najnowszego możliwego haka i nigdy nie próbuj wstępnie obliczać niczego, czego nie musisz.
źródło