Nonce, полученный из REST API, является недопустимым и отличается от nonce, сгенерированного в wp_localize_script

Для тех, кто прибывает из Google: вы вероятно, должны 'получить nonces из REST API , если вы действительно не знаете, что делаете. Аутентификация на основе файлов cookie с API REST предназначена только для для плагинов и тем. Для одностраничного приложения вы, вероятно, должны использовать OAuth .

Этот вопрос существует, потому что в документации нет /не было ясно, как вы должны аутентифицироваться при создании одностраничных приложений, JWT не подходят для веб-приложений, а OAuth сложнее реализовать, чем на основе файлов cookie.


В руководстве приведен пример как клиент Backbone JavaScript обрабатывает nonces, и если я следую примеру, я получаю nonce, который принимает встроенные конечные точки, такие как /wp /v2 /posts.

\wp_localize_script("client-js", "theme", [
  'nonce' => wp_create_nonce('wp_rest'),
  'user' => get_current_user_id(),

]);

Однако использование Backbone не может быть и речи, так что это темы, поэтому я написал следующий плагин:

<?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,
      ];
    },
  ]);
});

Я немного поиграл в консоль JavaScript и написал следующее:

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()

Ожидаемый результат - два новых сообщения, но я получаю Cookie nonce is invalid от первого, а второй создает сообщение успешно. Это, вероятно, потому, что нонцы разные, но почему? Я зарегистрировался как один и тот же пользователь в обоих запросах.

 введите описание изображения здесь>> </a> </p>

<p> Если мой подход ошибочен, как мне получить nonce? </p>

<p> <strong> Edit </STRONG> </p>

<p> Я пробовал возиться с globals <strike> без большой удачи </strike>. Получилось немного удачнее, используя действие wp_loaded: </p>

<pre><code>---- +: = 4 = + ----</code></pre>

<p> Теперь, когда я запускаю JavaScript выше, создаются два сообщения, но проверка конечной точки не выполняется! </p>

<p> <a href= введите описание изображения здесь>> </a> </p>

<p> Я отправился на отладку wp_verify_nonce: </p>

<pre><code>---- +: = 5 = + ----</code></pre>

<p> Я добавил несколько протоколов </p>

<pre><code>---- +: = 6 = + ----</code></pre>

<p> и код JavaScript теперь приводит к следующим записям. Как вы можете видеть, когда вызывается конечная точка проверки, uid равно 0. </p>

<pre><code>---- +: = 7 = + ----</code></pre></body></html>

7 голосов | спросил Christian 28 FebruaryEurope/MoscowbWed, 28 Feb 2018 19:43:29 +0300000000pmWed, 28 Feb 2018 19:43:29 +030018 2018, 19:43:29

3 ответа


3

Посмотрите более подробно на function rest_cookie_check_errors().

Когда вы получаете nonce через /wp-json/nonce/v1/get, вы не отправляете nonce в первую очередь. Таким образом, эта функция аннулирует вашу аутентификацию с помощью этого кода:

if ( null === $nonce ) {
    // No nonce at all, so act as if it's an unauthenticated request.
    wp_set_current_user( 0 );
    return true;
}

Вот почему вы получаете другое nonce от своего звонка REST и получаете его из темы. Звонок REST намеренно не распознает ваши учетные данные (в этом случае через файл cookie), потому что вы не отправили действительное значение nonce в запросе get.

Теперь причина, по которой ваш wp_loaded работал, заключалась в том, что вы получили nonce и сохранили его в глобальном порядке до того, как этот код останова аннулирует ваш логин. Проверка завершается с ошибкой, потому что код останова сводит на нет ваш логин до завершения проверки.

ответил Otto 1 MarpmThu, 01 Mar 2018 17:00:09 +03002018-03-01T17:00:09+03:0005 2018, 17:00:09
1

В то время как это решение работает, не рекомендуется . OAuth является предпочтительным выбором.


Я думаю, что понял.

I think , что wp_verify_nonce сломан, так как wp_get_current_user не может получить правильный пользовательский объект.

Это не так, как показано Отто.

К счастью, у него есть фильтр: $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );

Используя этот фильтр, я смог написать следующее, и код JavaScript будет выполнен следующим образом:

 введите описание изображения здесь>> </a> </p>

<pre><code>---- +: = 1 = + ----</code></pre>

<p> Если вы заметили проблему безопасности с исправлением, пожалуйста, дайте мне крик, прямо сейчас я не вижу ничего плохого в этом, кроме глобалов. </p></body></html>

ответил Christian 1 MarpmThu, 01 Mar 2018 14:58:32 +03002018-03-01T14:58:32+03:0002 2018, 14:58:32
0

Глядя на весь этот код, кажется, что ваша проблема заключается в использовании закрытий. На этапе init вы должны устанавливать только крючки и не оценивать данные, поскольку не все ядра закончили загрузку и инициализацию.

В

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,
      ];
    },
  ]);

$user привязан рано, чтобы использоваться в закрытии, но никто не обещает вам, что cookie уже обработан, и пользователь был аутентифицирован на их основе. Лучшим кодом будет

add_action('rest_api_init', function () {
  register_rest_route('nonce/v1', 'get', [
    'methods' => 'GET',
    'callback' => function () {
    $user = get_current_user_id();
      return [
        'nonce' => $GLOBALS['nonce'],
        'user' => $user,
      ];
    },
  ]);

Как всегда, с помощью чего-либо в Wordpress, используйте последний доступный крючок и никогда не пытайтесь подсчитать все, что вам не нужно.

ответил Mark Kaplun 1 MarpmThu, 01 Mar 2018 15:37:55 +03002018-03-01T15:37:55+03:0003 2018, 15:37:55

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132