简体   繁体   中英

WordPress API Permission Callback – Check if user is logged in

I have a question about permission callbacks when working with the WP Rest API. I have registered a couple of endpoints using register_rest_route and simply want to secure them so that you can't access the content if you're not logged in.

add_action('rest_api_init', 'register_custom_endpoints');

function register_custom_endpoints(){
    register_rest_route($base, $endpoint, [
        'methods' => 'POST',
        'callback' => function($request){
            // Return JSON data
        },
        'permission_callback' => function($request){
            // This always returns false
            return is_user_logged_in();
        },
    ]);
}

I think my logic here is correct but is_user_logged_in() always returns false, meaning I'll never get the data even if I'm actually logged in. All I get is a 404 response:

{code: "rest_user_invalid_id", message: "Invalid user ID.", data: {status: 404}}

I've been scouring the web for answers and what I've found is that I need to send a nonce with the request. I've tried sending it both as body data and as a header. If I send it in the body, I can't verify it as it always returns false. And if I send it as a header, I get the same 404 response as stated above.

What am I missing here, and what am I doing wrong?

I recently encountered the same issue and it turns out that you need to create a nonce and pass it with your request headers.

You create the appropriate nonce with the following php code.

$nonce = wp_create_nonce( 'wp_rest' );

Then you pass that nonce with the HTTP request via the header X-WP-Nonce .

Assuming your client is on the same domain (ergo has WordPress's auth cookies set) your session should be accessible via the REST API so functions like current_user_can and is_user_logged_in work as they would outside the REST API.

you can use current_user_can( 'edit_posts' );

it will only allow to admin user it work with me

for more info go to https://developer.wordpress.org/reference/functions/current_user_can/

A simple way to solve this is instead of permission_callback parameter that check user logged in status in the request handler function with a GET request URL parameter. You can add logged in user ID or a temporary generated nonce / hash in the URL and check on server side that they are the same or not, for example: domain.tld/wp-json/user/1/todo/

class UserAPI
{
    public function __construct()
    {
        // do nothing
    }

    public function setHooks()
    {
        add_action('rest_api_init', [$this, 'actionRestApiInit']);
    }

    public function actionRestApiInit()
    {
        // add current user ID into GLOBALS to get it in the request handler function
        $GLOBALS['user_id'] = get_current_user_id();

        register_rest_route(
            'user',
            '(?P<userID>\d+)/(?P<action>[a-zA-Z0-9-]+)/',
            [
                'methods' => 'GET',
                'callback' => [$this, 'runAction'],
            ]
        );
    }

    public function runAction(\WP_REST_Request $data=null)
    {
        $params = $data->get_params();

        if ((int)$params['userID']!==(int)$GLOBALS['user_id']) {
            return new \WP_Error( 'rest_forbidden', __('Sorry, you are not allowed to do that.'), ['status' => 401] );
        }

        wp_send_json(['Logged in, run api'], 200);
    }
}

(new UserAPI())->setHooks();

Or as a rest route attribute:

register_rest_route(
    'user',
    '(?P<userID>\d+)/(?P<action>[a-zA-Z0-9-]+)/',
    [
        'methods'   => 'GET',
        'callback'  => [$this, 'userActions'],
        'user_ID'   => get_current_user_id(),
    ]
);

and than:

if ( (int) $params['userID'] !== (int) $data->get_attributes()['user_ID'] )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM