Bagi mereka yang datang dari Google: Anda mungkin tidak seharusnya mendapatkan nonces dari REST API , kecuali jika Anda benar - benar tahu apa yang Anda lakukan. Otentikasi berbasis cookie dengan REST API hanya dimaksudkan untuk plugin dan tema. Untuk aplikasi satu halaman, Anda mungkin harus menggunakan OAuth .
Pertanyaan ini ada karena dokumentasi tidak / tidak jelas tentang bagaimana seharusnya Anda benar-benar mengotentikasi saat membuat aplikasi satu halaman, JWT tidak benar-benar cocok untuk aplikasi web, dan OAuth lebih sulit untuk diimplementasikan daripada autentikasi berbasis cookie.
Buku pegangan ini memiliki contoh tentang bagaimana klien Backbone JavaScript menangani masalah nonses, dan jika saya mengikuti contoh tersebut, saya mendapatkan nilai negatif yang diterima oleh titik akhir bawaan seperti / wp / v2 / posts.
\wp_localize_script("client-js", "theme", [
'nonce' => wp_create_nonce('wp_rest'),
'user' => get_current_user_id(),
]);
Namun, menggunakan Backbone keluar dari pertanyaan, dan begitu pula tema, jadi saya menulis plugin berikut:
<?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,
];
},
]);
});
Saya bermain-main di konsol JavaScript sedikit, dan menulis yang berikut:
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()
Hasil yang diharapkan adalah dua posting baru, tapi saya dapatkan Cookie nonce is invalid
dari yang pertama, dan yang kedua membuat posting dengan sukses. Itu mungkin karena nonce berbeda, tetapi mengapa? Saya masuk sebagai pengguna yang sama di kedua permintaan.
Jika pendekatan saya salah, bagaimana saya harus mendapatkan kesempatan?
Edit :
Saya mencoba main-main dengan global tanpa banyak keberuntungan . Menjadi sedikit lebih beruntung dengan memanfaatkan tindakan 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,
];
},
]);
});
Sekarang ketika saya menjalankan JavaScript di atas, dua posting dibuat, tetapi titik akhir verifikasi gagal!
Saya pergi ke debug 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!
Saya menambahkan beberapa logging
// 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;
}
dan kode JavaScript sekarang menghasilkan entri berikut. Seperti yang Anda lihat, ketika titik akhir verifikasi dipanggil, uid adalah 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
sumber
$_GET['nonce']
, tetapi header atau$_GET['_wpnonce']
parameter nonce . Benar?Meskipun solusi ini berfungsi, tidak disarankan . OAuth adalah pilihan yang lebih disukai.
Saya rasa saya mengerti.
Saya pikir wp_verify_nonce rusak, karena wp_get_current_user gagal mendapatkan objek pengguna yang tepat.Tidak seperti yang diilustrasikan oleh Otto.
Untungnya memiliki filter:
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
Dengan menggunakan filter ini, saya dapat menulis yang berikut ini, dan kode JavaScript dijalankan seperti seharusnya:
Jika Anda menemukan masalah keamanan dengan perbaikannya, tolong beri saya teriakan, saat ini saya tidak dapat melihat ada yang salah dengan perbaikannya, selain global.
sumber
Melihat semua kode ini, sepertinya masalah Anda adalah penggunaan penutupan. Pada
init
tahap Anda hanya perlu mengatur kait dan tidak mengevaluasi data karena tidak semua inti telah selesai memuat dan diinisialisasi.Di
yang
$user
terikat awal untuk digunakan dalam penutupan, tapi tidak ada janji-janji kepada Anda bahwa cookie sudah ditangani dan pengguna telah dikonfirmasi didasarkan pada mereka. Kode yang lebih baik adalahSeperti biasa dengan kait apa pun di wordpress, gunakan kait terbaru yang mungkin dan jangan pernah mencoba untuk menghitung ulang apa pun yang tidak harus Anda lakukan.
sumber