Die Funktion wp_get_current_user () funktioniert nicht in der Rückruffunktion der Rest-API

8

Betrachten Sie die folgende Klasse.

<?php
class MCQAcademy_Endpoint extends WP_REST_Controller {

    /**
     * Register the routes for the objects of the controller.
     */
    public function register_routes() {
        $version = '1';
        $namespace = 'custompath/v' . $version;
        $base = 'endpointbase';

        register_rest_route(
            $namespace,
            '/' . $base,
            array(
                array(
                    'methods'         => WP_REST_Server::READABLE,
                    'callback'        => array( $this, 'get_items' ),
                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
                    'args'            => array(),
                )
            )
        );
    }

    /**
     *
     */
    public function get_items( $request ) {
        $rs = array(
            'data' => array(),
            'request' => array(
                'lang' => 'en',
            ),
        );

        $args = array();
        $items = get_posts( $args );

        foreach( $items as $item ) {
            $itemdata = $this->prepare_item_for_response( $item, $request );
            $rs['data'][] = $this->prepare_response_for_collection( $itemdata );
        }

        $rs['wp_get_current_user'] = wp_get_current_user(); // Does not output as expected

        return new WP_REST_Response( $rs, 200 );
    }

    /**
     * Check if a given request has access to get items
     */
    public function get_items_permissions_check( $request ) {
        return true; // to make readable by all
    }


    /**
     * Prepare the item for create or update operation
     */
    protected function prepare_item_for_database( $request ) {
        return $request;
    }

    /**
     * Prepare the item for the REST response
     */
    public function prepare_item_for_response( $item, $request ) {
        $data = array(
            'ID' => $item->ID,
            'post_content' => wpautop($item->post_content),
            'post_title' => $item->post_title,
        );

        return $data;
    }

    /**
     * Get the query params for collections
     */
    public function get_collection_params() {
        return array(
            'page'     => array(
                'description'        => 'Current page of the collection.',
                'type'               => 'integer',
                'default'            => 1,
                'sanitize_callback'  => 'absint',
            ),
            'per_page' => array(
                'description'        => 'Maximum number of items to be returned in result set.',
                'type'               => 'integer',
                'default'            => 10,
                'sanitize_callback'  => 'absint',
            ),
            'search'   => array(
                'description'        => 'Limit results to those matching a string.',
                'type'               => 'string',
                'sanitize_callback'  => 'sanitize_text_field',
            ),
        );
    }

    // Register our REST Server
    public function hook_rest_server(){
        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
    }
}

$myEndpoint = new MCQAcademy_Endpoint();
$myEndpoint->hook_rest_server();

Alles läuft gut, außer dass der Aufruf der wp_get_current_user()Funktion in der get_items()Funktion einen leeren Benutzer zurückgibt, obwohl sich der Benutzer logged inauf der Website befindet.

Shah Alom
quelle

Antworten:

10

Auf Ihrer Website angemeldet bedeutet nicht, dass der Benutzer in der REST-API-Anforderung authentifiziert ist. Aus diesem Grund erhalten Sie nicht den richtigen Benutzer oder einen Id = 0

Bitte sehen Sie sich die REST-API-Authentifizierungsmethoden in den Dokumenten an:
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

Für Entwickler, die manuelle Ajax-Anfragen stellen, muss die Nonce bei jeder Anfrage übergeben werden. Die API verwendet Nonces mit der Aktion wp_rest. Diese können dann über den Datenparameter _wpnonce (entweder POST-Daten oder in der Abfrage nach GET-Anforderungen) oder über den X-WP-Nonce-Header an die API übergeben werden. Wenn keine Nonce angegeben ist, setzt die API den aktuellen Benutzer auf 0 und verwandelt die Anforderung in eine nicht authentifizierte Anforderung, selbst wenn Sie bei WordPress angemeldet sind.

Für die Remote-Authentifizierung würde ich das JWT-Plugin für einen schnellen Start empfehlen:
https://es.wordpress.org/plugins/jwt-authentication-for-wp-rest-api/

Oder Sie können die in den Dokumenten vorgeschlagenen verwenden:
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#authentication-plugins

Pabamato
quelle
1
Ich benötige eine Benutzer-ID, wenn der Benutzer auf der Site angemeldet ist. Da der Endpunkt geöffnet ist, muss die Berechtigung nicht überprüft werden.
Shah Alom
Diese Zeile gibt immer false zurück, obwohl der Benutzer auf der Website angemeldet ist. $rs['wp_get_current_user'] = is_user_logged_in() ? get_current_user_id() : false;
Shah Alom
2
Für die Cookie-Authentifizierung: Für Entwickler, die manuelle Ajax-Anforderungen stellen, muss das Nonce bei jeder Anforderung übergeben werden. Die API verwendet Nonces mit der Aktion wp_rest. Diese können dann über den Datenparameter _wpnonce (entweder POST-Daten oder in der Abfrage nach GET-Anforderungen) oder über den X-WP-Nonce-Header an die API übergeben werden. Wenn keine Nonce angegeben ist, setzt die API den aktuellen Benutzer auf 0 und verwandelt die Anforderung in eine nicht authentifizierte Anforderung, selbst wenn Sie bei WordPress angemeldet sind.
Pabamato
1
Selbst bei der JWT-Authentifizierung müssen Sie den X-WP-Nonce-Header noch übergeben, um den aktuellen Benutzer abzurufen. Wenn Sie beispielsweise auf Benutzer zugreifen müssen, gibt me / me weiterhin 401 zurück, dies gilt auch für Abfragebenutzer nach Rolle usw. Die "nicht manuellen" AJAX-Anforderungen sind "speziell", nur weil der offizielle API-Client diesen Header enthält, aber sonst nichts.
Jesús Franco
2
@ JesúsFranco Sie haben Recht, für serverseitige Anfragen (mein Fall) wird das Token ausreichen, für clientseitige / manuelle Ajax-Aufrufe müssen Sie das Nonce einschließen, um CSRF zu vermeiden. Es ist nicht erforderlich, das Token einzuschließen, da Sie dies bereits tun habe einen angemeldeten Benutzer und Client-Seite ist Cookie-basiert
Pabamato
1

Um ein voll funktionsfähiges Codebeispiel zu erhalten, finden Sie hier ein Beispiel-Plugin zum Abrufen der aktuellen Benutzer-ID über REST.

my-plugin.php

class MyPlugin {

  public function __construct() {

    add_action('wp_enqueue_scripts', [$this, 'scripts']);
    add_action('rest_api_init', [$this, 'rest']);
  }

  function scripts() {

    // Add JS.
    wp_enqueue_script('my-plugin', plugin_dir_url(__FILE__) . 'js/scripts.js', ['jquery'], NULL, TRUE);
    // Pass nonce to JS.
    wp_localize_script('my-plugin', 'MyPluginSettings', [
      'nonce' => wp_create_nonce('wp_rest'),
    ]);
  }

  function rest() {

    // Register route.
    register_rest_route('my-plugin/v1', '/uid', [
      'methods'  => WP_REST_Server::READABLE,
      'callback' => [$this, 'rest_callback'],
    ]);
  }

  function rest_callback($data) {

    // Get current user ID.
    $data = [
      'uid' => get_current_user_id(),
    ];

    $response = new WP_REST_Response($data, 200);
    // Set headers.
    $response->set_headers(['Cache-Control' => 'must-revalidate, no-cache, no-store, private']);

    return $response;
  }

}

new MyPlugin();

js / scripts.js

(function($) {

  $(document).ready(function() {

    var settings = MyPluginSettings;

    $.ajax({
      url: '/wp-json/my-plugin/v1/uid',
      method: 'GET',
      beforeSend: function(xhr) {
        xhr.setRequestHeader('X-WP-Nonce', settings.nonce);
      }
    }).done(function(response) {

      // Will return your UID.
      console.log(response);
    });

  });

})(jQuery);

Ressource: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

Leymannx
quelle
Ich verstehe nicht, wie 'MyPluginSettings' an das Skript übergeben wird. Mögliche Dinge zu beachten: Ich verwende derzeit nicht JQuery, sondern "Vanille" JavaScript ... Ich habe mein Skript bei Bedarf in HTML-Tags <script> eingefügt, aber ich habe versucht, sie in wp_enqueue_script aufzunehmen, und habe das gleiche Problem festgestellt.
TTT
1
Ich habe das zum Laufen gebracht, ich hatte einen falschen Pfad geschrieben, als ich mich für wp_enqueue_script () angepasst habe. Aber ich hatte auch mehrere Skripte und ich habe gerade verstanden, dass der erste Parameter von wp_enqueue_script () nicht spezifisch für das Plug-In ist, sondern spezifisch für das Skript (vielleicht sollten Sie 'my-plugin' in Ihrer Antwort ändern, weil das verwirrend ist .
TTT
@TTT - Tauschen Sie es my-scriptzum Beispiel mit? Ja, es sollte nur ein eindeutiger Handle-Name sein, der häufig den Namen des Plugins oder Themas enthält.
Leymannx
1

wp_get_current_user()funktioniert nicht, weil Ihr Benutzer nicht perfekt eingestellt ist. Siehe unten stehenden Code /wp-includes/user.phpals Referenz.

if ( ! empty( $current_user ) ) {
    if ( $current_user instanceof WP_User ) {
        return $current_user;
    }

    // Upgrade stdClass to WP_User
    if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
        $cur_id       = $current_user->ID;
        $current_user = null;
        wp_set_current_user( $cur_id );
        return $current_user;
    }

    // $current_user has a junk value. Force to WP_User with ID 0.
    $current_user = null;
    wp_set_current_user( 0 );
    return $current_user;
}

if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
    wp_set_current_user( 0 );
    return $current_user;
}

Sie müssen lediglich wp_set_current_user ({user_id}) am Anfang Ihrer API verwenden.

user3308965
quelle
0

Wenn ein API-Aufruf eingeht, für den kein Nonce festgelegt ist, wird die Anforderung von WordPress de-authentifiziert, wodurch der aktuelle Benutzer beendet und die Anforderung nicht authentifiziert wird. Dieser CSFR-Schutz erfolgt automatisch, und Sie müssen nichts tun, damit er funktioniert, außer das Nonce einzuschließen.

Der Weg, dies zu lösen, besteht darin, eine Nonce einzuschließen. Etwas wie das:

$_wpnonce = wp_create_nonce( 'wp_rest' );
echo "<input type = 'hidden' name = '_wpnonce' value = '$_wpnonce' />";

Und nehmen Sie es in Ihre API-Anfrage auf. Die Nonce muss "_wpnonce" heißen und die Aktion muss "wp_rest" sein, damit die API funktioniert. Es kann in die URL oder in den Post-Body gehen.

John Dee
quelle