社区新闻

开发者视角:WordPress 登录与注册如何运作?

查看官方原文 ↗ 发布于

在为 WordPress 开发用户认证系统时,深刻理解登录和注册流程至关重要。本文将阐明这些流程的复杂性,以及确保 WordPress 站点中用户获得安全、无缝体验的底层函数。通过本文档,开发者将对 WordPress 中登录和注册的工作原理,以及如何挂钩到流程的每一步以实现自定义功能有一个全面的认识。

Registration in WordPress

WordPress 中的登录如何工作?

要登录 WordPress 站点,用户需要通过位于 /wp-login.php 端点的登录表单输入其凭据。此端点可以通过自定义代码更改,但默认情况下,它仍是登录端点。此表单就像一个网关,用户在此提供用户名和密码。用户提交此信息后,会向服务器发送一个 POST 类型的请求。该请求随后由 wp-login.php 文件处理,该文件是整个登录过程的主要入口。

在 wp-login.php 中,使用 wp_authenticate() 函数验证用户凭据。如果提供的用户名和密码与数据库记录匹配,则用户通过认证。否则,会触发一个 WP Error

Authenticate 过滤器

插件开发者可以使用 authenticate 过滤器来拦截此过程,并引入额外的验证步骤或替代的认证方法。这使得集成外部认证提供者或高级安全机制成为可能。下面,你将找到一个如何为登录过程添加自定义验证逻辑的示例。

function wporg_custom_login_validation($user, $username, $password) {
    // 你可以在此添加自定义验证逻辑
    if (some_custom_condition()) {
        return new WP_Error('custom_error', __('Custom validation failed.', 'your-text-domain'));
    }
    return $user;
}
add_filter('authenticate', 'wporg_custom_login_validation', 10, 3);

你也可以为登录页面添加自定义字段。例如,下面演示了如何添加一个必选的复选框,用户必须勾选后才能登录。

function wporg_custom_login_field(){
?>
    <p>
        <label for="my_extra_field">I agree to the terms and conditions</label>
        <input type="checkbox" value="1" class="input" id="custom_login_field" name="custom_login_field_name"/>
    </p>
<?php
}
add_action('login_form','wporg_custom_login_field');

function wporg_check_checkbox($user, $password) {
    if( !isset($_POST['custom_login_field_name']) )
    {
        remove_action('authenticate', 'wp_authenticate_username_password', 20);
        $user = new WP_Error( 'denied', __('<strong>ERROR</strong>: Please agree to our terms and conditions to login.', 'your-text-domain') );
    }
    return $user;
}
add_filter( 'wp_authenticate_user', 'wporg_check_checkbox', 10, 3 );

Cookie 的设置

一旦认证过程成功,WordPress 会生成认证 Cookie。这些 Cookie 就像数字标记,有助于维持用户的会话。WordPress 中用于认证的两个最重要的 Cookie 是:

  • wordpress_logged_in_{hash}
  • wordpress_sec_{hash}

现在,这些新创建的认证 Cookie 需要放入用户的浏览器中。WordPress 使用 setcookie() 函数来实现。这样,用户浏览器与服务器之间的任何进一步交互都会包含这些 Cookie。它允许服务器持续识别和验证用户的会话,而无需用户每次都输入用户名和密码。

一旦这些 Cookie 成功设置在浏览器中,用户通常会被重定向到 WordPress 仪表板或他们登录前试图访问的确切页面。这些 Cookie 的默认过期时间是两天,除非在登录表单上勾选了记住我;否则 Cookie 将保留 14 天。

wordpress_logged_in_{hash} Cookie:此 Cookie 包含一个根据用户名、过期时间和密钥生成的特殊代码(哈希)。当此 Cookie 在浏览器中设置后,系统会将用户识别为已认证并已登录。

wordpress_sec_{hash} Cookie:这个 Cookie 也包含一个哈希,但这次它是使用用户的会话 ID、过期时间戳和与之前相同的密钥生成的。此 Cookie 的目的是双重检查用户的认证会话,为过程增加额外的安全层。

自定义认证 Cookie

认证 Cookie 的生成和处理可以使用动作和过滤器进行自定义。

set_auth_cookie 动作使开发者能够修改 Cookie 创建和插入的行为,从而增强会话管理或引入自定义 Cookie 数据。

下面,你将找到一个示例,展示如何将默认的 Cookie 过期时间增加到七天,如果用户勾选了记住我,则增加到 30 天。

function wporg_auth_cookie_expiration_filter($expiration, $user_id, $remember) {
    if ($remember) {
        return strtotime('+30 days', 0); //30 天,以秒计。
    } else {
        return 604800; //7 天,以秒计。
    }
}
add_filter('auth_cookie_expiration', 'wporg_auth_cookie_expiration_filter', 10, 3);

如上所述,在用户在网站上的活动会话期间,每次用户请求新页面时都会检查这些认证 Cookie。WordPress 依赖一个名为 wp_validate_auth_cookie() 的函数来执行这项基本任务。它确保用户的会话保持活动和有效。如果 Cookie 仍然有效(即未过期)且状态正常,则用户仍处于登录状态,可以继续使用站点。

但是,如果 Cookie 缺失或已过期,系统将要求用户重新登录,从登录表单开始。下面的代码示例展示了如何根据 Cookie 是否有效来执行特定任务。

$user_id = get_current_user_id(); // 获取当前用户的 ID

if ($user_id) {
    // 用户已登录,验证认证 Cookie
    $auth_cookie = $_COOKIE[LOGGED_IN_COOKIE];
    $auth_cookie_valid = wp_validate_auth_cookie($auth_cookie, 'logged_in');

    if ($auth_cookie_valid) {
        // 认证 Cookie 有效,据此执行操作
        echo __('Authentication cookies are valid.', 'your-text-domain');
    } else {
        // 认证 Cookie 无效,采取适当措施
        echo __('Authentication cookies are not valid. Please log in again.', 'your-text-domain');
    }
} else {
    // 用户未登录,相应处理
    echo __('User is not logged in.', 'your-text-domain');
}

用户成功登录后,开发者可以使用 is_user_logged_in() 函数来检查特定用户是否已登录,然后相应地触发某些操作。例如:

if (is_user_logged_in()) {
    // 用户已登录,执行特定操作
    echo __('Welcome, logged-in user!', 'your-text-domain');
} else {
    // 用户未登录,执行其他操作
    echo __('Please login to access this content.', 'your-text-domain');
}

WordPress 中的注册如何工作?

要在 WordPress 站点上注册,最终用户通常需要导航到注册页面或表单,通常可通过 /wp-login.php?action=register 端点访问。注册过程通常涉及输入基本详细信息,如用户名、电子邮件、密码等。如果注册期间需要额外字段,可以使用 register_form 动作钩子添加。例如,具有编码知识的管理员可以使用提供的代码片段通过添加“电话号码”等字段来自定义注册表单:

function wporg_custom_registration_form() {
   ?>
   <p>
        <label for="phone">Phone Number<br>
           <input type="text" name="phone" id="phone" class="input" value="">
        </label>
    </p>
    <?php
}
add_action('register_form', 'wporg_custom_registration_form');

提交填写好的注册表单后,会向 wp-login.php 文件发送一个 POST 请求。该文件管理注册并验证用户输入。要对注册期间用户提交的数据执行自定义验证,可以使用 registration_errors 过滤器。在下面的示例中,代码验证了上面添加的电话号码条目。

function wporg_custom_registration_validation($errors, $sanitized_user_login, $user_email) {
    if (empty($_POST['phone'])) {
        $errors->add('phone_error', __('Phone number is required.', 'textdomain'));
    }
    return $errors;
}
add_filter('registration_errors', 'wporg_custom_registration_validation', 10, 3);

使用 user_register 动作钩子,将从注册过程中收集的附加信息存储为用户元数据。下面的代码示例用于存储电话号码。

function wporg_save_phone_number($user_id) {
   if (isset($_POST['phone'])) {
        $phone = sanitize_text_field($_POST['phone']);
        update_user_meta($user_id, 'phone_number', $phone);
     }
}
add_action('user_register', 'wporg_save_phone_number');

提交的用户数据经过全面的验证和清理过程。WordPress 利用 sanitize_user()sanitize_email() 等函数来确保提供的用户名和电子邮件不包含潜在有害内容,从而实现干净、安全的输入。

为了确保电子邮件地址的唯一性,WordPress 会检查提供的电子邮件是否已与现有帐户关联。email_exists() 函数用于确定电子邮件是否已注册。

出于安全考虑,用户选择的密码会通过强大的加密算法进行哈希处理。wp_hash_password() 函数在此过程中扮演核心角色,将明文密码转换为加固的哈希值,从而增强用户凭据的安全性。请注意,目前 WordPress 使用 MD5 哈希技术对密码进行哈希处理。如果想实现自定义密码哈希,可以轻松地使用 wp_hash_password 过滤器来完成。

function wporg_custom_password_hash($password) {
    $hashed_password = my_custom_hash_function($password); 
    // 这里的 my_custom_hash_function 将是哈希函数
    return $hashed_password;
}
add_filter('wp_hash_password', 'wporg_custom_password_hash');

在成功验证、检查用户名可用性并确认电子邮件唯一性之后,通过 wp_insert_user() 函数在 WordPress 数据库中创建一个新的用户帐户。此函数将用户信息无缝集成到 wp_users 表中。

根据站点的配置,用户可能需要通过发送到其注册电子邮件地址的激活链接来激活其帐户。WordPress 利用 wp_send_new_user_notifications() 函数向用户和站点管理员发送电子邮件通知,告知他们新的注册信息。

与登录过程类似,WordPress 会创建认证 Cookie,为新注册的用户构建一个会话。会生成 wordpress_logged_in_{hash}wordpress_sec_{hash} Cookie,其中包含关键的用户会话数据。

然后,这些认证 Cookie 使用 setcookie() 函数嵌入到用户的浏览器中,就像用户登录时一样。在这种情况下,也会持续调用 wp_validate_auth_cookie() 函数,在每次页面请求时验证这些 Cookie,从而保护用户在网站内的无缝参与。

对于注册后的操作,例如发送通知或执行额外的数据库操作,可以使用像 user_register 这样的钩子。这允许你在用户成功注册时触发自定义操作。这有助于根据特定要求定制电子邮件内容和通知。例如,下面演示了如何自定义注册期间发送的电子邮件通知:

function wporg_custom_registration_email($user_id) {
    $user = get_userdata($user_id);
    $to = $user->user_email;
    $subject = __('Welcome to Our Website', 'your-text-domain');
    $message = __('Thank you for registering on our website. This is a custom email notification.', 'your-text-domain');

    // 在此自定义电子邮件内容

    wp_mail($to, $subject, $message);
}
add_action('wp_new_user_notification', 'wporg_custom_registration_email');

关于登录和注册的补充说明

在创建用户或登录时,密码中的任何前导或尾随空格都会被自动修剪。因此,密码前后出现的空格将不被考虑。但需要注意的是,只有当空格出现在实际密码文本内部时,才会被视为密码的一部分。

例如,如果密码是“Testtest  “,则空格不会被计入。但是,如果密码是“Test  test”,则空格会被考虑,并且在登录时,需要使用确切数量的空格来进行认证。

所有电子邮件地址都会被转换为小写,因此无论你的电子邮件地址包含大写字母还是小写字母,在将值保存到数据库/与数据库中的值进行比较时,它们总是会被转换为小写字母。

电子邮件中允许使用撇号。

WordPress 的密码哈希算法在每次密码更改时都会生成不同的哈希值。因此,即使你将密码更改为现有的密码,也会生成另一个新的哈希值,并作为条目保存在 wp_users 表中。

多站点:密码找回邮件中的链接将始终指向主站点。例如,如果子站点 A 的任何用户尝试使用子站点 B 的用户名和密码登录,他会被自动重定向到子站点 A。当发起密码重置时,请求通过主站点处理。同时,系统会要求用户通过主站点的域名链接重置密码。在电子邮件中,也会使用该主站点的名称。