Come configurare correttamente un nonce AJAX per l'API REST di WordPress?

13 set 2019, 13:37:57
Visualizzazioni: 16.4K
Voti: 8

Seguendo un commento con link qui che mi ha portato a questa documentazione, ho provato a configurare un nonce per l'autenticazione degli utenti.

Ho aggiunto:

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

all'istruzione if che verifica se l'utente è loggato e può eseguire le operazioni richieste dalla chiamata REST.

Ho anche aggiunto:

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

alla mia classe jQuery che effettua la chiamata API.

Ho ricevuto un errore che mi diceva che wpApiSettings non esiste. Cosa ho sbagliato?

0
Tutte le risposte alla domanda 1
3
28

Prima di tutto..

(Questa informazione è per altri lettori che non lo sanno ancora.) Ci sono due modi per autenticare la tua richiesta REST API:

Puoi leggere di più sul manuale ufficiale della REST API qui, e questa risposta riguarda l'autenticazione standard via cookie, dove il nonce dovrebbe essere inviato tramite un parametro di query GET/POST chiamato _wpnonce o un header (HTTP personalizzato) chiamato X-WP-Nonce.

Opzioni per inviare il nonce del cookie

  • Opzione semplice: Aggiungi _wpnonce all'URL dell'endpoint REST API. Funziona con richieste GET, POST, ecc. inclusi payload JSON.

    jQuery.ajax({
        method: 'POST',
    
        // _wpnonce come parametro di query GET/$_GET
        url: '/path/to/endpoint?_wpnonce=<nonce>',
    
        data: { foo: 'bar', baz: 1 },
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • Oppure aggiungi _wpnonce al corpo della richiesta.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
    
        // _wpnonce come parametro di query POST/$_POST
        // ma può essere GET; vedi il `method` sopra che di default è GET quando non specificato
        data: { foo: 'bar', baz: 1, _wpnonce: '<nonce>' },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • O in particolare quando invii un payload JSON (proprio come il codice di esempio in questa domanda): Aggiungi X-WP-Nonce agli header della richiesta. Questa opzione funziona bene anche con richieste GET, POST, ecc.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
        data: JSON.stringify( { foo: 'bar', baz: 1 } ), // inviando una stringa codificata JSON
        contentType: 'application/json; charset=utf-8', // e un header Content-Type JSON
    
        // Invia il nonce come parte degli header.
        beforeSend: function ( xhr ) {
            xhr.setRequestHeader( 'X-WP-Nonce', '<nonce>' );
        },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    

Ora un esempio:

Parte PHP: (nel file functions del tuo tema o nel file del tuo plugin)

// Registra un endpoint REST API fittizio..
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(),
                'L\'utente è loggato: ' . ( is_user_logged_in() ? 'Sì' : 'NO' ),
                'L\'utente può pubblicare post: ' . ( current_user_can( 'publish_posts' ) ? 'Sì' : 'NO' )
            ];
        },
    ] );
}

add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
    // Includi lo script che effettua la chiamata AJAX a /wp-json/my-plugin/v1/foo.
    wp_enqueue_script( 'my-script', '/path/to/my-script.js', [ 'jquery' ] );

    // Registra variabili personalizzate per lo script AJAX.
    wp_localize_script( 'my-script', 'myScriptVars', [
        'root'  => esc_url_raw( rest_url() ),
        'nonce' => wp_create_nonce( 'wp_rest' ),
    ] );
}

Note:

  1. Ricorda che il primo parametro per wp_enqueue_script()my-script nell'esempio sopra — è esattamente lo stesso del primo parametro per wp_localize_script(). E quel parametro è l'handle dello script, che è uno slug univoco come identificatore per lo script che stai includendo o localizzando.

  2. Se quei parametri non corrispondono, allora lo script non verrebbe localizzato, e l'oggetto JS — myScriptVars nell'esempio sopra — sarebbe undefined il che potrebbe risultare in un errore come quello menzionato nella domanda ("wpApiSettings non esiste"). :)

Parte JS: (in my-script.js o qualsiasi sia il nome del file...)

Qui, aggiungiamo _wpnonce al corpo della richiesta.

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

Note:

Il codice JS sopra e gli altri in questa risposta utilizzano ajax() di jQuery.

13 set 2019 14:59:33
Commenti

Ah, certo! Mi sento così stupido, ovviamente la localizzazione deve essere fatta prima degli header. Doh. Ottima risposta.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 set 2019 16:39:11

Nota per i più lenti tra noi (come me) il primo parametro di wp_localize_script è l'handle con cui hai registrato il tuo script per metterlo in coda.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 set 2019 17:13:53

Grazie, l'ho aggiunto alla risposta.. :)

Sally CJ Sally CJ
13 set 2019 18:12:21