WordPress自定义密码恢复页面显示“errors=invalidkey”错误

3

我使用WordPress v5.4.1,并有以下代码来从自定义页面发送密码重置邮件。

按照https://code.tutsplus.com/tutorials/build-a-custom-wordpress-user-flow-part-3-password-reset--cms-23811的教程操作。

// Custom message
function replace_retrieve_password_message($message, $key, $user_login, $user_data) {

    global $wpdb;

    $key = $wpdb->get_var("SELECT user_activation_key FROM $wpdb->users WHERE user_login ='" . $user_login . "'");
    if (empty($key)) {
        //generate reset key
        $key = wp_generate_password(20, false);
        $wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
    }
    // Create new message
    $msg = __('Hello!') . "\r\n\r\n";
    $msg .= sprintf(__('You asked us to reset your password for your account using the email address %s.'), $user_login) . "\r\n\r\n";
    $msg .= __("If this was a mistake, or you didn't ask for a password reset, just ignore this email and nothing will happen.") . "\r\n\r\n";
    $msg .= __('To reset your password, visit the following address:') . "\r\n\r\n";
    $msg .= site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "\r\n\r\n";
    $msg .= __('Thanks!') . "\r\n";

    return $msg;
}

add_filter('retrieve_password_message', 'replace_retrieve_password_message', 10, 4);

用户收到密码重置邮件,但在单击链接时出现errors=invalidkey错误。
我尝试删除自定义的$key函数以使用WordPress默认密钥生成。这样我会有密码重置页面,但是任何操作都会显示errors = invalidkey


在 site_url 中,您将 'key=$key' 替换为 'key={$key}'。 - CharlesEF
仍然存在“errors=invalidkey”错误。 - theKing
2个回答

3
为什么要重新生成$key?为什么不只使用传递给回调函数的$key?
但是,如果你必须重新生成它,那么你可以使用 get_password_reset_key()
$key = get_password_reset_key( $user_data );

1
你的 invalidkey 错误的原因是你只是创建了随机密码并直接使用它。要使其成为有效的重置密钥,需要对其进行哈希处理。
参考资料: https://core.trac.wordpress.org/browser/tags/5.4/src/wp-includes/user.php#L2316 因此,如果你想使用你的方法,你只需要像这样对你的密钥进行哈希处理,
// Custom message
function replace_retrieve_password_message($message, $key, $user_login, $user_data) {

    global $wpdb;
    global $wp_hasher;

    $key = $wpdb->get_var("SELECT user_activation_key FROM $wpdb->users WHERE user_login ='" . $user_login . "'");
    if (empty($key)) {
        //generate reset key
        $key = wp_generate_password(20, false);

        if ( empty( $wp_hasher ) ) {
            require_once ABSPATH . WPINC . '/class-phpass.php';
            $wp_hasher = new PasswordHash( 8, true );
        }

        $key = time() . ':' . $wp_hasher->HashPassword( $key );

        $wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
    }
    // Create new message
    $msg = __('Hello!') . "\r\n\r\n";
    $msg .= sprintf(__('You asked us to reset your password for your account using the email address %s.'), $user_login) . "\r\n\r\n";
    $msg .= __("If this was a mistake, or you didn't ask for a password reset, just ignore this email and nothing will happen.") . "\r\n\r\n";
    $msg .= __('To reset your password, visit the following address:') . "\r\n\r\n";
    $msg .= site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "\r\n\r\n";
    $msg .= __('Thanks!') . "\r\n";

    return $msg;
}

add_filter('retrieve_password_message', 'replace_retrieve_password_message', 10, 4);

我写这个只是为了让你更好地理解这个问题,但我不建议这样做。
推荐的方法是:
正如其他答案所建议的那样,正确的做法是跳过所有手动进行的密钥创建,并使用正确的函数,即get_password_reset_key(),因此采用这种方法的代码如下:
// Custom message
function replace_retrieve_password_message($message, $key, $user_login, $user_data) {

    $key = get_password_reset_key( $user_data );

    // Create new message
    $msg = __('Hello!') . "\r\n\r\n";
    $msg .= sprintf(__('You asked us to reset your password for your account using the email address %s.'), $user_login) . "\r\n\r\n";
    $msg .= __("If this was a mistake, or you didn't ask for a password reset, just ignore this email and nothing will happen.") . "\r\n\r\n";
    $msg .= __('To reset your password, visit the following address:') . "\r\n\r\n";
    $msg .= site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "\r\n\r\n";
    $msg .= __('Thanks!') . "\r\n";

    return $msg;
}

add_filter('retrieve_password_message', 'replace_retrieve_password_message', 10, 4);

正如您所看到的,它更加干净。在可用和适用的情况下最好使用现有的功能。


第一种方法直接给了我“errors=invalidkey”错误。第二种方法“$key = get_password_reset_key( $user_data );”带我到了密码重置页面,但是在输入密码后出现了“errors=invalidkey”错误。 - theKing
@theKing,这段代码可能不是罪魁祸首。除了这个过滤器之外,您使用的其他代码也可能存在问题。 - Shahbaz A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接