Как правильно настроить AJAX nonce для WordPress REST API?

13 сент. 2019 г., 13:37:57
Просмотры: 16.4K
Голосов: 8

Следуя комментарию с ссылкой здесь, который привел меня к этой документации, я попытался настроить nonce для аутентификации пользователя.

Я добавил:

wp_localize_script( 'wp-api', 'wpApiSettings', array(
    'root' => esc_url_raw( rest_url() ),
    'nonce' => wp_create_nonce( 'wp_rest' )
) );

в условие if, проверяющее, что пользователь вошел в систему и может выполнять действия, запрашиваемые в REST вызове.

Я также добавил:

        beforeSend: function ( xhr ) {
            xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
        },

в свой jQuery класс для API вызова.

Я получил ошибку, сообщающую, что wpApiSettings не существует. Что я сделал не так?

0
Все ответы на вопрос 1
3
28

Для начала...

(Эта информация для тех читателей, кто еще не знает об этом.) Существует два способа аутентификации REST API запросов:

Подробнее можно прочитать в официальном руководстве по REST API здесь, а этот ответ посвящен стандартной аутентификации через куки, где nonce должен быть передан либо через параметр запроса GET/POST с именем _wpnonce, либо через (пользовательский HTTP) заголовок с именем X-WP-Nonce.

Варианты отправки nonce через куки

  • Простой вариант: Добавить _wpnonce в URL конечной точки REST API. Работает с запросами GET, POST и другими, включая JSON-данные.

    jQuery.ajax({
        method: 'POST',
    
        // _wpnonce как параметр GET/$_GET запроса
        url: '/path/to/endpoint?_wpnonce=<nonce>',
    
        data: { foo: 'bar', baz: 1 },
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • Или добавить _wpnonce в тело запроса.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
    
        // _wpnonce как параметр POST/$_POST запроса
        // но может быть GET; смотрите параметр `method` выше, который по умолчанию GET, если не указан
        data: { foo: 'bar', baz: 1, _wpnonce: '<nonce>' },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • Или, особенно при отправке JSON-данных (как в примере кода в этом вопросе): Добавить X-WP-Nonce в заголовки запроса. Этот вариант также хорошо работает с запросами GET, POST и другими.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
        data: JSON.stringify( { foo: 'bar', baz: 1 } ), // отправка строки в формате JSON
        contentType: 'application/json; charset=utf-8', // и заголовок Content-Type для JSON
    
        // Отправить nonce как часть заголовков.
        beforeSend: function ( xhr ) {
            xhr.setRequestHeader( 'X-WP-Nonce', '<nonce>' );
        },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    

Теперь пример:

PHP часть: (в файле функций вашей темы или файле плагина)

// Регистрация тестовой конечной точки REST API..
add_action( 'rest_api_init', 'my_register_rest_routes' );
function my_register_rest_routes() {
    register_rest_route( 'my-plugin/v1', '/foo', [
        'methods'  => 'POST',
        'callback' => function ( $request ) {
            return [
                $request->get_params(),
                'Пользователь авторизован: ' . ( is_user_logged_in() ? 'Да' : 'Нет' ),
                'Может ли пользователь публиковать записи: ' . ( current_user_can( 'publish_posts' ) ? 'Да' : 'Нет' )
            ];
        },
    ] );
}

add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
    // Подключение скрипта, который делает AJAX запрос к /wp-json/my-plugin/v1/foo.
    wp_enqueue_script( 'my-script', '/path/to/my-script.js', [ 'jquery' ] );

    // Регистрация пользовательских переменных для AJAX скрипта.
    wp_localize_script( 'my-script', 'myScriptVars', [
        'root'  => esc_url_raw( rest_url() ),
        'nonce' => wp_create_nonce( 'wp_rest' ),
    ] );
}

Примечания:

  1. Помните, что первый параметр для wp_enqueue_script()my-script в примере выше — должен совпадать с первым параметром для wp_localize_script(). Этот параметр является уникальным идентификатором (handle) скрипта, который вы подключаете или локализуете.

  2. Если эти параметры не совпадают, скрипт не будет локализован, и JS объект — myScriptVars в примере выше — будет undefined, что может привести к ошибке, такой как упомянутая в вопросе ("wpApiSettings does not exist"). :)

JS часть: (в файле my-script.js или другом, в зависимости от названия...)

Здесь мы добавляем _wpnonce в тело запроса.

jQuery.ajax({
    method: 'POST',
    url: myScriptVars.root + 'my-plugin/v1/foo',
    data: { foo: 'bar', baz: 1, _wpnonce: myScriptVars.nonce },
    dataType: 'json',
    success: function ( data ) {
        console.log( data );
    },
});

Примечания:

Код выше, как и другой JS код в этом ответе, использует jQuery ajax().

13 сент. 2019 г. 14:59:33
Комментарии

Ах, конечно! Я чувствую себя таким глупым, конечно, локализация должна быть выполнена до заголовков. Блин. Отличный ответ.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 сент. 2019 г. 16:39:11

Заметка для самых медленных среди нас (вроде меня) - первый параметр wp_localize_script - это handle, с которым вы зарегистрировали свой скрипт при его постановке в очередь.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 сент. 2019 г. 17:13:53

Спасибо, я добавил это в ответ.. :)

Sally CJ Sally CJ
13 сент. 2019 г. 18:12:21