Смена пароля через AJAX с помощью WordPress REST API
Я создаю форму смены пароля с помощью WordPress REST API. Пользователь вводит новый пароль, который затем передается через AJAX в пользовательскую конечную точку, которая делает следующее:
$userID = get_current_user_id();
wp_set_password($password, $userID);
//Log user in and update auth cookie
wp_set_current_user($userID);
wp_set_auth_cookie($userID);
//Set the cookie immediately
$_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($userID, 2 * DAY_IN_SECONDS);
//Return fresh nonce
return new WP_Rest_Response(array(
'nonce' => wp_create_nonce('wp_rest')
));
Конечная точка должна автоматически войти в систему пользователя и вернуть новый nonce, чтобы ему не пришлось снова входить в систему с новым паролем.
Проблема в том, что nonce возвращается точно так же и является недействительным. Я могу получить новый nonce только после обновления страницы. Кажется, что некоторые $_COOKIE или $_SESSION переменные, которые WordPress использует для генерации nonces, не обновляются до обновления страницы.
Спасибо за вашу помощь.
2 ответов:
Похоже, что некоторые переменные $_COOKIE или $_SESSION, которые WordPress полагается на генерацию nonces не обновляется до тех пор, пока страница обновить.
Да, и это так.
LOGGED_IN_COOKIE, по умолчанию используется:'wordpress_logged_in_' . COOKIEHASHВзгляните на:
$token = wp_get_session_token();вwp_create_nonce()
$cookie = wp_parse_auth_cookie( '', 'logged_in' );вwp_get_session_token()
$cookie_name = LOGGED_IN_COOKIE;вwp_parse_auth_cookie()Поэтому вы заменили бы этот код: (и я бы не стал используйте
wp_generate_auth_cookie()Для этой цели; и вместо этого используйте то, что уже было сгенерировано черезwp_set_auth_cookie())//Set the cookie immediately $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($userID, 2 * DAY_IN_SECONDS);..с этим:
$_set_cookies = true; // for the closures // Set the (secure) auth cookie immediately. We need only the first and last // arguments; hence I renamed the other three, namely `$a`, `$b`, and `$c`. add_action( 'set_auth_cookie', function( $auth_cookie, $a, $b, $c, $scheme ) use( $_set_cookies ){ if ( $_set_cookies ) { $_COOKIE[ 'secure_auth' === $scheme ? SECURE_AUTH_COOKIE : AUTH_COOKIE ] = $auth_cookie; } }, 10, 5 ); // Set the logged-in cookie immediately. `wp_create_nonce()` relies upon this // cookie; hence, we must also set it. add_action( 'set_logged_in_cookie', function( $logged_in_cookie ) use( $_set_cookies ){ if ( $_set_cookies ) { $_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie; } } ); // Set cookies. wp_set_auth_cookie($userID); $_set_cookies = false;Рабочий пример (протестирован на WordPress 4.9.5)
PHP / WP REST API
function myplugin__change_password( $password, $userID ) { //$userID = get_current_user_id(); wp_set_password($password, $userID); // Log user in. wp_set_current_user($userID); $_set_cookies = true; // for the closures // Set the (secure) auth cookie immediately. We need only the first and last // arguments; hence I renamed the other three, namely `$a`, `$b`, and `$c`. add_action( 'set_auth_cookie', function( $auth_cookie, $a, $b, $c, $scheme ) use( $_set_cookies ){ if ( $_set_cookies ) { $_COOKIE[ 'secure_auth' === $scheme ? SECURE_AUTH_COOKIE : AUTH_COOKIE ] = $auth_cookie; } }, 10, 5 ); // Set the logged-in cookie immediately. `wp_create_nonce()` relies upon this // cookie; hence, we must also set it. add_action( 'set_logged_in_cookie', function( $logged_in_cookie ) use( $_set_cookies ){ if ( $_set_cookies ) { $_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie; } } ); // Set cookies. wp_set_auth_cookie($userID); $_set_cookies = false; //Return fresh nonce return new WP_Rest_Response(array( 'nonce' => wp_create_nonce('wp_rest'), 'status' => 'password_changed', )); } function myplugin_change_password( WP_REST_Request $request ) { $old_pwd = $request->get_param( 'old_pwd' ); $new_pwd = $request->get_param( 'new_pwd' ); $user = wp_get_current_user(); if ( ! wp_check_password( $old_pwd, $user->user_pass, $user->ID ) ) { return new WP_Error( 'wrong_password', 'Old password incorrect' ); } if ( $old_pwd !== $new_pwd ) { return myplugin__change_password( $new_pwd, $user->ID ); } return new WP_Rest_Response( [ 'nonce' => wp_create_nonce( 'wp_rest' ), 'status' => 'passwords_equal', ], 200 ); } add_action( 'rest_api_init', function(){ register_rest_route( 'myplugin/v1', '/change-password', [ 'methods' => 'POST', 'callback' => 'myplugin_change_password', 'args' => [ 'old_pwd' => [ 'type' => 'string', 'validate_callback' => function( $param ) { return ! empty( $param ); } ], 'new_pwd' => [ 'type' => 'string', 'validate_callback' => function( $param ) { return ! empty( $param ); } ], ], 'permission_callback' => function(){ // Only logged-in users. return current_user_can( 'read' ); }, ] ); } );HTML / форма
<fieldset> <legend>Change Password</legend> <p> To change your password, please enter your old or current password. </p> <label> Old Password: <input id="old_passwd"> </label> <label> New Password: <input id="new_passwd"> </label> <label> Old nonce: (read-only) <input id="old_nonce" value="<?= wp_create_nonce( 'wp_rest' ) ?>" readonly disabled> </label> <label> New nonce: (read-only) <input id="new_nonce" readonly disabled> </label> <button id="go" onclick="change_passwd()">Change</button> </fieldset> <div id="rest-res"><!-- AJAX response goes here --></div>JQuery / AJAX
function change_passwd() { var apiurl = '/wp-json/myplugin/v1/change-password', $ = jQuery; $.post( apiurl, { old_pwd: $( '#old_passwd' ).val(), new_pwd: $( '#new_passwd' ).val(), _wpnonce: $( '#new_nonce' ).val() || $( '#old_nonce' ).val() }, function( res ){ $( '#new_nonce' ).val( res.nonce ); // Update the global nonce for scripts using the `wp-api` script. if ( 'object' === typeof wpApiSettings ) { wpApiSettings.nonce = res.nonce; } $( '#rest-res' ).html( '<b>Password changed successfully.</b>' ); }, 'json' ).fail( function( xhr ){ try { var res = JSON.parse( xhr.responseText ); } catch ( err ) { return; } if ( res.code ) { $( '#rest-res' ).html( '<b>[ERROR]</b> ' + res.message ); } }); }
Вам нужно передать nonce через заголовок
X-WP-Nonceс вашим запросом AJAX. Что-то вроде:beforeSend: function ( xhr ) { xhr.setRequestHeader( 'X-WP-Nonce', localizedScript.nonce ); }Где
localizedScript- это скрипт, на который локализован ваш nonce. Дополнительную информацию о локализации смотрите в Кодексе. Примечание методlocalizedScriptне требуется.Без
localizedSriptВаш AJAX может выглядеть следующим образом:var _nonce = "<?php echo wp_create_nonce( 'wp_rest' ); ?>"; $.ajax({ type: 'POST', url: url_path, data: {}, dataType: 'json', beforeSend: function ( xhr ) { xhr.setRequestHeader( 'X-WP-Nonce', _nonce ); } });Очевидно, что копирование этого точного сценария выше не поможет сделать это за вас, но именно так вам нужно передать nonce успешно.
Comments