WordPress-REST-API-Authentifizierung mit Fetch

Lesezeit: 5 Minuten

Ich versuche zu verwenden Cookie-Authentifizierung für den Zugriff auf die WordPress-REST-API mithilfe der API abrufendie Authentifizierung schlägt jedoch mit dem folgenden Fehler fehl.

403: Cookie Nonce ist ungültig

Ich verwende das folgende Skript, um eine Verbindung zur API herzustellen.

const headers = new Headers({
   'Content-Type': 'application/json',
   'X-WP-Nonce': WPAPI.nonce
});  

fetch(WPAPI.root + 'my-endpoint/upload/', {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(data)
})

Wenn ich von der Verwendung von Fetch zu wechsle XMLHttpRequest es funktioniert wie erwartet.

let request = new XMLHttpRequest();
request.open('POST', WPAPI.root + 'my-endpoint/upload/', true);
request.setRequestHeader('X-WP-Nonce', WPAPI.nonce);
request.setRequestHeader('Content-Type', 'application/json');
request.send(JSON.stringify(data));

Gibt es möglicherweise ein Problem mit der Art und Weise, wie Header in der Fetch-Methode gesendet werden?

Die WordPress-Nonce-Authentifizierung erfordert die Verwendung von Cookies und standardmäßig sendet Fetch diese nicht mit. Sie können die Option “Anmeldeinformationen” verwenden, damit dies funktioniert:

fetch(endpoint, {
  credentials: 'same-origin'
})

https://github.com/github/fetch#sending-cookies

Bin auf meinen Beitrag von vor 4 Jahren gestoßen, auf der Suche nach dem gleichen Problem 🙂 Dies löst das Problem.

const response = await fetch(url, {
    method: 'POST',
    credentials: 'same-origin',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce' : my_var.nonce
    },
    body: JSON.stringify(data),
});
const content = await response.json();
console.log(content);

Benutzer-Avatar
Jürgen Fink

Spät, aber vielleicht hilfreich für andere Leser, da ich Code speziell für hinzugefügt habe bringen() Versprechen nach dieser Frage.

WordPress verwendet einmal automatisch in ihren Cookies, wie ich herausgefunden habe.

WordPress: Version 5.7.2
PHP: Version 7.4
Gastgeber: hostmonster.com
Klient: Windows 10
Browser: getestet auf Chrome, Firefox, sogar Edge 😜 hat funktioniert

Code (PHP Code in der function.php Ihres installierten Themes):

add_action('rest_api_init', function() {
    /**
     * Register here your custom routes for your CRUD functions
     */
    register_rest_route( 'my-endpoint/v1', '/upload/', array(
        array(
            'methods'  => WP_REST_Server::READABLE, // = 'GET'
            'callback' => 'get_data',
            // Always allow, as an example
            'permission_callback' => '__return_true'
        ),
        array(
            'methods'  => WP_REST_Server::CREATABLE, // = 'POST'
            'callback' => 'create_data',
            // Here we register our permissions callback
            // The callback is fired before the main callback to check if the current user can access the endpoint
            'permission_callback' => 'prefix_get_private_data_permissions_check',
        ),
    ));
});

// The missing part:
// Add your Permission Callback function here, that checks for the cookie
// You should define your own 'prefix_' name, though

function prefix_get_private_data_permissions_check() {
    
    // Option 1: Password Protected post or page:
    // Restrict endpoint to browsers that have the wp-postpass_ cookie.
    if ( !isset($_COOKIE['wp-postpass_'. COOKIEHASH] )) {
        return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not create or edit private data.', 'my-text-domain' ), array( 'status' => 401 ) );
    };

    // Option 2: Authentication based on logged-in user:
    // Restrict endpoint to only users who have the edit_posts capability.
    if ( ! current_user_can( 'edit_posts' ) ) {
        return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not create or edit private data.', 'my-text-domain' ), array( 'status' => 401 ) );
    };
 
    // This is a black-listing approach. You could alternatively do this via white-listing, by returning false here and changing the permissions check.
    return true;
};

function create_data() {
    global $wpdb;

    $result = $wpdb->query(...);

    return $result;
}

function get_data() {
    global $wpdb;

    $data = $wpdb->get_results('SELECT * from `data`');

    return $data;
}

Stellen Sie sicher, dass Sie es in Ihre HTML-Seite aufnehmen credentials: 'same-origin' in Ihrer HTTP-Anforderung, wie in den vorherigen Antworten und Kommentaren oben richtig angegeben.

Code (HTML mit Inline <script> ... </script>):

<script>

// Here comes the REST API part:
// HTTP requests with fetch() promises

function getYourData() {
  let url="https://example.com/wp-json/my-endpoint/v1/upload/";
  fetch(url, {
    method: 'GET',
    credentials: 'same-origin', // <-- make sure to include credentials
    headers:{
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        //'Authorization': 'Bearer ' + token  <-- not needed, WP does not check for it
    }
  }).then(res => res.json())
  .then(response => get_success(response))
  .catch(error => failure(error));
};

function insertYourData(data) {
  let url="https://example.com/wp-json/my-endpoint/v1/upload/";
  fetch(url, {
    method: 'POST',
    credentials: 'same-origin', // <-- make sure to include credentials
    headers:{
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        //'Authorization': 'Bearer ' + token  <-- not needed, WP does not check for it
    },
    body: JSON.stringify(data)
  }).then(res => res.json())
  .then(response => create_success(response))
  .catch(error => failure(error));
};

// your Success and Failure-functions:

function get_success(json) {
  // do something here with your returned data ....
  console.log(json);
};

function create_success(json) {
  // do something here with your returned data ....
  console.log(json);
};

function failure(error) {
  // do something here ....
  console.log("Error: " + error);
};

</script>

Abschließende Gedanken:

Ist 'Authorization': 'Bearer ' + token notwendig im Header der HTTP-Anfrage?

Nach einigem Testen wurde mir das klar if ( !isset($_COOKIE['wp-postpass_'. COOKIEHASH] )) { ... innerhalb der Berechtigungsrückruf prüft nicht nur, ob das Cookie im Client-Browser gesetzt ist, aber es scheint auch seinen Wert zu überprüfen (das JWT-Token).

Weil ich wie bei meinem ursprünglichen Code doppelt überprüft habe, ein falsches Token übergebe, das Cookie lösche oder die Sitzung offen lasse, aber im Back-End das Passwort der Website ändere (daher würde WordPress ein neues Token erstellen, daher der Wert set wp_postpass_ Cookie würde sich ändern) und alle Tests verliefen korrekt – REST-API blockiert, wodurch nicht nur das Vorhandensein eines Cookies, sondern auch sein Wert überprüft wird (was gut ist – danke WordPress-Team).

Quellen:

Ich habe die folgende Ressource zu den obigen Gedanken in der gefunden FAQ-Bereich:

Warum überprüft die REST-API den eingehenden Origin-Header nicht? Setzt dies meine Website CSRF-Angriffen aus?

Da die WordPress-REST-API den Origin-Header eingehender Anfragen nicht überprüft, kann daher von jeder Seite aus auf öffentliche REST-API-Endpunkte zugegriffen werden. Dies ist eine bewusste Designentscheidung.

WordPress verfügt jedoch über einen bestehenden CSRF-Schutzmechanismus, der Nonces verwendet.

Und nach meinen bisherigen Tests Die WP-Authentifizierung funktioniert einwandfrei.

Daumen hoch 👍 für das WordPress-Team

Zusätzliche 2 Quellen aus dem WordPress REST-API-Handbuch:

REST-API-Handbuch / Erweiterung der REST-API / Routen und Endpunkte
REST-API-Handbuch / Erweitern der REST-API / Hinzufügen benutzerdefinierter Endpunkte

Und 1 Quelle aus WordPress Code-Referenz betreffend rest_cookie_check_errors() Funktion:

Referenz / Funktionen / rest_cookie_check_errors()

Für diejenigen, die an der vollständigen Geschichte meiner Ergebnisse interessiert sind, folgen Sie dem Link zu meinem Thread mit Antworten, Code-Snippets und zusätzlichen Ergebnissen.

So erzwingen Sie die Authentifizierung auf der REST-API für eine passwortgeschützte Seite mit einer benutzerdefinierten Tabelle und fetch() ohne Plugin

1371630cookie-checkWordPress-REST-API-Authentifizierung mit Fetch

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy