Изменение пароля с помощью AJAX с помощью API WordPress REST

Я создаю форму смены пароля с помощью 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')
));

Конечная точка должна автоматически войти в систему и вернуть новый одноразовый номер, чтобы ему не приходилось снова входить в систему со своим новым паролем.

Проблема в том, что возвращаемый одноразовый номер точно такой же и недействительный. Я могу получить новый одноразовый номер только после обновления страницы. Кажется, что некоторые $_COOKIE или же $_SESSION Переменные, на которые опирается WordPress для генерации одноразовых номеров, не обновляются до обновления страницы.

Спасибо за вашу помощь.

7

Решение

Кажется, что некоторые переменные $ _COOKIE или $ _SESSION, которые WordPress
полагается на создание одноразовых номеров не обновляются, пока страница
обновить.

Да, и это LOGGED_IN_COOKIE, который по умолчанию:

'wordpress_logged_in_' . COOKIEHASH

Взгляни на:

Так что вы бы заменить этот код: (и я бы не стал использовать 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 );
}
});
}
8

Другие решения

Вы должны передать одноразовый номер через 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 );
}
});

Очевидно, что копирование этого точного сценария выше привычка сделайте это за вас, но это, по сути, то, как вам нужно успешно передать одноразовый номер.

1

По вопросам рекламы [email protected]