从REST_API返回相同的wp_rest随机数

时间:2020-11-02 作者:Rob

TLDR:如何强制返回一个新的nonce,以便AJAX在不刷新页面的情况下工作

从以下位置开始Nonces and Ajax request to REST API and verification 我实现了Nonce功能,具有回调权限,路由的“意图”现在是安全的。

我将Axios排队,将wp\\u rest nonce作为本地脚本设置。

    // Register custom variables for the AJAX script.
    wp_localize_script( \'axios\', \'axiosScriptVars\', [
        \'root\'  => esc_url_raw( rest_url() ),
        \'nonce\' => wp_create_nonce( \'wp_rest\' ),
    ]);
我使用axiosScriptVars设置Ajax标头。暂时的。我发布了这篇文章。我从REST\\U API端点的响应中返回一个NONCE,并更新我的Ajax头,为下一篇文章做好准备。。。

我的登录和注销路由示例:

function ajax_logout() {
    try {
    wp_logout();
    $nonce = wp_create_nonce( \'wp_rest\' );
    return array(\'loggedin\'=>false, \'message\'=>__(\'Logged out successfully\'), \'name\'=>false, \'email\'=>false, \'nonce\'=>$nonce );
    } catch (Exception $e) {
        echo \'Caught exception: \',  $e->getMessage(), "\\n";
        die;
    }
}


function ajax_login(){
    $_POST = json_decode(file_get_contents("php://input"),true);

    $info = array();
    $info[\'user_login\'] = !empty($_POST[\'username\']) ? sanitize_text_field( $_POST[\'username\'] ) : null;
    $info[\'user_password\'] = !empty( $_POST[\'password\'] ) ? sanitize_text_field( $_POST[\'password\'] ) : null;
    $info[\'remember\'] = true;
    
    $user = wp_signon( $info, true );
    $nonce = wp_create_nonce( \'wp_rest\' );

    if ( is_wp_error($user) ){
        return array(\'loggedin\'=>false, \'message\'=>__(\'Wrong username or password.\'), \'name\'=>false, \'email\'=>false, \'nonce\'=>$nonce );
    } else {
        return array(\'loggedin\'=>true, \'message\'=>__(\'Login successful\'), \'name\'=>$user->data->display_name, \'email\'=>$user->data->user_email, \'nonce\'=>$nonce );
    }
}


add_action( \'rest_api_init\', function () {
    register_rest_route( \'rw-user/v1\', \'/log-in\', array(
        \'methods\' => \'POST\',
        \'callback\' => \'ajax_login\',
        \'permission_callback\' => \'__return_true\'
    ));
    register_rest_route(\'rw-user/v1\',\'/log-out\', array(
        \'methods\' => \'POST\',
        "callback" => \'ajax_logout\',
        "permission_callback" => function () {
            return current_user_can( \'read\' );
        }
    ));
});
过帐失败,因为新的NONCE与旧的相同。

所以我认为Wordpress必须在响应头中返回一个新的nonce。。。我查看并查看;x-wp-nonce“;标题-只有它也是相同的!

(我读到一些关于在REST路由中不使用wp\\u json\\u success的内容,因为REST api已经将函数的返回转换为json响应,并设置了正确的头等。)

当我硬刷新页面时,我得到了一个新的nonce,我的AJAX现在可以工作了。。。

如何强制返回一个新的nonce,以便AJAX在不刷新页面的情况下工作?

这篇帖子有点类似-Serving nonces through AJAX is not refreshing nonce, returning 403 error, 但是我在我的代码中看不到任何更改用户和使nonce无效的内容。。。

除非登录路由(现在已登录)更改nonce,否则不会返回该nonce?

编辑

我已经用Sally的答案进行了重构。一切正常(尽管我不得不清除浏览器缓存,因为发生了一些奇怪的事情)。

    // https://wordpress.stackexchange.com/questions/377570/identical-wp-rest-nonce-returned-from-rest-api

/* Ajax REST cookie stuff */
// https://remonpel.nl/2018/06/wordpress-rest-api-nonce-sense/

add_action(\'set_logged_in_cookie\', function($cookie_value){
    $_COOKIE[ LOGGED_IN_COOKIE ] = $cookie_value;
}, PHP_INT_MAX);

// on log-ou, clear the global $_COOKIE the same way wp_logout() does.
// todo: see if more cookies need this.
add_action(\'clear_auth_cookie\', function(){
    $_COOKIE[ LOGGED_IN_COOKIE ] = \' \';
});

/* end Ajax REST cookie stuff */


function ajax_logout() {
    wp_logout();
    wp_set_current_user(0);
    return [
        \'loggedin\'  =>  false,
        \'message\'   =>  __(\'Logged out successfully\'),
        \'name\'      =>  false,
        \'email\'     =>  false,
    ];
}


function ajax_login($request){
    $user = wp_signon( array(
        \'user_login\'    => $request->get_param( \'username\' ),
        \'user_password\' => $request->get_param( \'password\' ),
        \'remember\'      => true,
    ));
      // In case of errors like wrong password, return the error object/data.
if ( is_wp_error( $user ) ) {
    $data = [
        \'failed\' => $user,
        \'nonce\'    =>   wp_create_nonce( \'wp_rest\' ),
    ];
    return new WP_REST_Response($data, 200); // important if you want to display data client side
}
    wp_set_current_user( $user->ID ); // super important
    return [
        \'loggedin\' =>   is_user_logged_in(),
        \'message\'  =>   __(\'Login successful\'), 
        \'name\'     =>   $user->data->display_name, 
        \'email\'    =>   $user->data->user_email,
        \'nonce\'    =>   wp_create_nonce( \'wp_rest\' ),
    ];
}



function read_permissions_check() {
    // Restrict endpoint to only users who have the edit_posts capability.
    // This can be extended or whatever
    if ( !current_user_can( \'read\' ) ) {
        return new WP_Error( \'rest_forbidden\', esc_html__( \'You shall not pass!\', \'my-text-domain\' ), array( \'status\' => 401 ) );
    }
    return true;
}


add_action( \'rest_api_init\', function () {
    register_rest_route( \'rw-user/v1\', \'/log-in\', array(
        \'methods\' => \'POST\',
        \'callback\' => \'ajax_login\',
        \'permission_callback\' => \'__return_true\',
    ));
    register_rest_route(\'rw-user/v1\',\'/log-out\', array(
        \'methods\' => \'POST\',
        "callback" => \'ajax_logout\',
        \'permission_callback\' => \'read_permissions_check\',
    ));
});

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

尽管你已经找到了答案solution, 由于这是另一个问题的后续问题,我认为发布这个答案会有好处,所以希望它能帮助您。=)

WordPress使用本机setcookie() PHP中用于设置身份验证Cookie的函数,以及$_COOKIE 用于读取Cookie值。但问题是,PHP不会立即更新$_COOKIE 数组,而仅在重新加载页面后更新。

因此,由于WordPress nonce依赖于当前用户和身份验证cookie,因此您需要执行这些操作,以便在非常相同的页面/请求上获得正确的nonce,即无需重新加载页面:

立即更新$_COOKIE 一旦你调用了数组wp_signon() (其中调用wp_set_auth_cookie()). 您可以使用set_logged_in_cookie hook.

然后打电话wp_set_current_user() 登录用户后-如果不调用它,生成的nonce将不会使用当前用户和以下函数is_user_logged_in()current_user_can() 也会返回false.

工作示例

function wpse_377570( $logged_in_cookie ) {
    $_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie;
}
add_action( \'set_logged_in_cookie\', \'wpse_377570\' );

function ajax_login( $request ) {
    // Logs the user in and set the authentication cookies.
    $user = wp_signon( array(
        \'user_login\'    => $request->get_param( \'username\' ),
        \'user_password\' => $request->get_param( \'password\' ),
        \'remember\'      => true,
    ) );

    // In case of errors like wrong password, return the error object/data.
    if ( is_wp_error( $user ) ) {
        return $user;
    }

    // Now set the current user so that we get the correct nonce based on
    // that user.
    wp_set_current_user( $user->ID );

    return [
        \'nonce\'    => wp_create_nonce( \'wp_rest\' ),
        \'loggedin\' => is_user_logged_in(),
        // ... your other data.
    ];
}
<附加说明REST API端点的回调始终接收请求对象(aWP_REST_Request 实例)作为第一个参数,其中get_param() 用于检索URL查询字符串、POST body数据或JSON负载等参数,因此您应该make use of that and the other functions, 正如我在示例中所做的那样。:)

相关推荐

JQuery AJAX未加载带有ACF字段的页面

我使用以下jQuery代码将内容从一个模板部分加载到另一个模板部分。如果没有ACF PHP标记,它就可以工作。但是,当我在中添加这些标记时<?php the_field(\'field_name\'); ?> 它抛出500(内部服务器错误)错误。请问有没有人能解决这个问题? var baseUrl = "http://projectname:8888/wp-content/themes/custom-theme" $(".cross