Cum să configurezi corect un nonce AJAX pentru API REST în WordPress

13 sept. 2019, 13:37:57
Vizualizări: 16.4K
Voturi: 8

Urmând un comentariu cu link aici care m-a condus la aceste documente, am încercat să configurez un nonce pentru autentificarea utilizatorilor.

Am adăugat:

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

la instrucțiunea if care verifică dacă utilizatorul este autentificat și poate face operațiunile cerute în apelul REST.

De asemenea, am adăugat:

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

la clasa jQuery a apelului meu API.

Am primit o eroare care îmi spune că wpApiSettings nu există. Ce am greșit?

0
Toate răspunsurile la întrebare 1
3
28

Pentru început...

(Această informație este pentru alți cititori care nu știu încă despre asta.) Există două modalități prin care vă puteți autentifica cererea REST API:

Puteți citi mai multe în manualul oficial REST API aici, iar acest răspuns este pentru autentificarea standard prin cookie, unde nonce-ul trebuie să fie trimis fie prin parametrul de interogare GET/POST numit _wpnonce, fie prin antetul (HTTP personalizat) numit X-WP-Nonce.

Opțiuni pentru trimiterea nonce-ului prin cookie

  • Opțiunea simplă: Adăugați _wpnonce la URL-ul endpoint-ului REST API. Aceasta funcționează cu cereri GET, POST, etc., inclusiv cu payload-uri JSON.

    jQuery.ajax({
        method: 'POST',
    
        // _wpnonce ca parametru de interogare GET/$_GET
        url: '/path/to/endpoint?_wpnonce=<nonce>',
    
        data: { foo: 'bar', baz: 1 },
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • Sau adăugați _wpnonce în corpul cererii.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
    
        // _wpnonce ca parametru de interogare POST/$_POST
        // dar poate fi GET; vedeți `method` de mai sus care implicit este GET când nu este specificat
        data: { foo: 'bar', baz: 1, _wpnonce: '<nonce>' },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    
  • Sau în special când trimiteți un payload JSON (exact ca în exemplul din această întrebare): Adăugați X-WP-Nonce în anteturile cererii. Această opțiune funcționează și cu cereri GET, POST, etc.

    jQuery.ajax({
        method: 'POST',
        url: '/path/to/endpoint',
        data: JSON.stringify( { foo: 'bar', baz: 1 } ), // trimiterea unui șir codificat JSON
        contentType: 'application/json; charset=utf-8', // și un antet Content-Type JSON
    
        // Trimiteți nonce-ul ca parte a antetelor.
        beforeSend: function ( xhr ) {
            xhr.setRequestHeader( 'X-WP-Nonce', '<nonce>' );
        },
    
        dataType: 'json',
        success: function ( data ) {
            console.log( data );
        },
    });
    

Acum un exemplu:

Partea PHP: (în fișierul de funcții al temei sau al plugin-ului)

// Înregistrați un endpoint dummy 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(),
                'Utilizator autentificat: ' . ( is_user_logged_in() ? 'Da' : 'NU' ),
                'Utilizatorul poate publica postări: ' . ( current_user_can( 'publish_posts' ) ? 'Da' : 'NU' )
            ];
        },
    ] );
}

add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
    // Încărcați scriptul care face apelul AJAX către /wp-json/my-plugin/v1/foo.
    wp_enqueue_script( 'my-script', '/path/to/my-script.js', [ 'jquery' ] );

    // Înregistrați variabile personalizate pentru scriptul AJAX.
    wp_localize_script( 'my-script', 'myScriptVars', [
        'root'  => esc_url_raw( rest_url() ),
        'nonce' => wp_create_nonce( 'wp_rest' ),
    ] );
}

Note:

  1. Amintiți-vă că primul parametru pentru wp_enqueue_script()my-script în exemplul de mai sus — este exact același cu primul parametru pentru wp_localize_script(). Și acel parametru este handle-ul scriptului, care este un slug unic ca identificator pentru scriptul pe care îl încărcați sau localizați.

  2. Dacă acei parametri nu se potrivesc, atunci scriptul nu va fi localizat, iar obiectul JS — myScriptVars în exemplul de mai sus — va fi undefined, ceea ce ar putea duce la eroarea menționată în întrebare ("wpApiSettings nu există"). :)

Partea JS: (în my-script.js sau oricare este numele fișierului...)

Aici, adăugăm _wpnonce în corpul cererii.

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:

Codul JS de mai sus și celelalte din acest răspuns folosesc ajax() din jQuery.

13 sept. 2019 14:59:33
Comentarii

Ah, desigur! Mă simt atât de prost, evident că localizarea trebuie făcută înaintea headerelor. Doh. Răspuns excelent.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 sept. 2019 16:39:11

Notă pentru cei mai lenți dintre noi (ca mine) - primul parametru al funcției wp_localize_script este handle-ul cu care ai înregistrat scriptul tău când l-ai adăugat în coadă.

Matthew Brown aka Lord Matt Matthew Brown aka Lord Matt
13 sept. 2019 17:13:53

Mulțumesc, am adăugat asta în răspuns.. :)

Sally CJ Sally CJ
13 sept. 2019 18:12:21