分析 `wp_set_auth_cookie()` 函数的源码,它是如何设置用户登录会话的 `Cookie` 的?

各位观众老爷们,晚上好! 今天咱就来唠唠 WordPress 里那个神秘又重要的 wp_set_auth_cookie() 函数,看看它到底是怎么把咱们登录状态“烙印”在浏览器上的,也就是设置用户登录会话的 Cookie 的。 准备好了吗? 咱们这就开讲!

一、Cookie 是个啥?为啥要用它?

在深入源码之前,先得搞清楚 Cookie 是个什么玩意儿。 简单来说,Cookie 就是服务器存储在咱们浏览器上的一小段文本信息。 每次咱们再访问同一个网站时,浏览器都会自动把这些 Cookie 发给服务器。

为啥要用 Cookie 呢? 因为 HTTP 协议是无状态的,也就是说,服务器记不住你上次是谁。 想象一下,你登录了一个网站,点了个商品加入购物车,然后你点到另一个页面,如果服务器不记得你已经登录了,那购物车里的商品岂不是就丢了? 这就尴尬了!

Cookie 就解决了这个问题。 通过 Cookie,服务器可以记住你的登录状态、购物车里的商品、个性化设置等等。

二、wp_set_auth_cookie() 函数: 登录的“烙印师”

wp_set_auth_cookie() 函数的作用就是设置验证 Cookie,告诉浏览器 "嘿,这个用户已经登录了,记住他!"。 它是 WordPress 用户验证机制的核心部分。

三、源码剖析: 一步一步揭秘 Cookie 的诞生

咱们现在就来扒一扒 wp_set_auth_cookie() 函数的源码,看看它到底是怎么“烙印” Cookie 的。

/**
 * Sets the authentication cookies.
 *
 * Stores the authentication details in a cookie. The cookie is used to
 * automatically sign in the user when they return to the site.
 *
 * @since 2.5.0
 *
 * @param int    $user_id User ID.
 * @param bool   $remember Whether to remember the user. Default is false.
 * @param mixed  $expiration Optional. Unix timestamp for when the cookie expires.
 *                           If `$remember` is true, defaults to 14 days from now.
 *                           If `$remember` is false, defaults to 12 hours from now.
 * @param string $scheme   Optional. Scheme to use. Default is 'auth'. Accepts 'auth', 'secure_auth', or 'logged_in'.
 */
function wp_set_auth_cookie( $user_id, $remember = false, $expiration = null, $scheme = 'auth' ) {
    $secure = is_ssl();

    if ( ! $expiration ) {
        if ( $remember ) {
            $expiration = time() + (int) apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
        } else {
            $expiration = time() + (int) apply_filters( 'auth_cookie_expiration', 12 * HOUR_IN_SECONDS, $user_id, $remember );
        }
    } else {
        $expiration = (int) $expiration;
    }

    $auth_cookie_name = AUTH_COOKIE;
    $scheme_cookie_name = $scheme . '_cookie';
    $logged_in_cookie = LOGGED_IN_COOKIE;

    if ( 'secure_auth' === $scheme ) {
        $auth_cookie_name = SECURE_AUTH_COOKIE;
        $logged_in_cookie = SECURE_LOGGED_IN_COOKIE;
        $secure = true;
    } elseif ( 'logged_in' === $scheme ) {
        $auth_cookie_name = LOGGED_IN_COOKIE;
        $secure = apply_filters( 'secure_logged_in_cookie', $secure, $user_id, $remember );
    }

    $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme );
    $scheme_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, 'token' );

    setcookie( $auth_cookie_name, $auth_cookie, $expiration, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
    setcookie( $scheme_cookie_name, $scheme_cookie, $expiration, COOKIEPATH, COOKIE_DOMAIN, $secure, true );

    if ( $remember ) {
        setcookie( 'wp-saving-post', 'checking', time() + 30, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true );
    }

    /**
     * Fires immediately after the authentication cookies are set.
     *
     * @since 3.7.0
     *
     * @param int    $user_id    User ID.
     * @param bool   $remember   Whether to remember the user.
     * @param string $expiration The time the auth cookie expires as a Unix timestamp.
     * @param string $scheme     The scheme to use. Default is 'auth'.
     */
    do_action( 'set_auth_cookie', $user_id, $remember, $expiration, $scheme );
}

咱们一行一行地拆解:

  1. 参数解析:

    • $user_id: 用户 ID,这个是必须的,告诉函数你要给哪个用户设置 Cookie。
    • $remember: 是否“记住我”,也就是是否设置一个有效期更长的 Cookie。 默认是 false,也就是不记住。
    • $expiration: Cookie 的过期时间,Unix 时间戳格式。 如果不传,函数会根据 $remember 的值来设置默认的过期时间。 记住我,默认14天过期,否则12小时。
    • $scheme: Cookie 的方案,默认是 auth。 还可以是 secure_authlogged_in。 这个参数决定了 Cookie 的名称。
  2. 判断是否是安全连接(HTTPS):

    $secure = is_ssl();

    is_ssl() 函数会判断当前是否是 HTTPS 连接。 如果是,$secure 就为 true,否则为 false。 这个变量会影响 Cookie 的 secure 标志,后面会讲到。

  3. 设置过期时间:

    if ( ! $expiration ) {
       if ( $remember ) {
           $expiration = time() + (int) apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
       } else {
           $expiration = time() + (int) apply_filters( 'auth_cookie_expiration', 12 * HOUR_IN_SECONDS, $user_id, $remember );
       }
    } else {
       $expiration = (int) $expiration;
    }

    这段代码根据 $remember 的值来设置 Cookie 的过期时间。 如果 $remembertrue,则过期时间为 14 天后,否则为 12 小时后。 注意,这里使用了 apply_filters() 函数,允许开发者通过过滤器来修改默认的过期时间。

    参数 说明
    time() 当前时间的 Unix 时间戳
    DAY_IN_SECONDS WordPress 定义的常量,表示一天有多少秒 (86400)
    HOUR_IN_SECONDS WordPress 定义的常量,表示一小时有多少秒 (3600)
    apply_filters() WordPress 的过滤器函数,允许开发者修改变量的值
    auth_cookie_expiration 过滤器名称,用于修改 Cookie 的过期时间
    $user_id 用户 ID
    $remember 是否“记住我”
  4. 确定 Cookie 名称:

    $auth_cookie_name = AUTH_COOKIE;
    $scheme_cookie_name = $scheme . '_cookie';
    $logged_in_cookie = LOGGED_IN_COOKIE;
    
    if ( 'secure_auth' === $scheme ) {
       $auth_cookie_name = SECURE_AUTH_COOKIE;
       $logged_in_cookie = SECURE_LOGGED_IN_COOKIE;
       $secure = true;
    } elseif ( 'logged_in' === $scheme ) {
       $auth_cookie_name = LOGGED_IN_COOKIE;
       $secure = apply_filters( 'secure_logged_in_cookie', $secure, $user_id, $remember );
    }

    这段代码根据 $scheme 的值来确定 Cookie 的名称。 WordPress 定义了几个常量来表示不同的 Cookie 名称:

    • AUTH_COOKIE: 默认的验证 Cookie 名称。
    • SECURE_AUTH_COOKIE: 用于 HTTPS 连接的验证 Cookie 名称。
    • LOGGED_IN_COOKIE: 用于“记住我”功能的 Cookie 名称。

    如果 $schemesecure_auth,则使用 SECURE_AUTH_COOKIE,并且强制 $securetrue,因为 secure_auth 只能用于 HTTPS 连接。
    如果 $schemelogged_in,则使用 LOGGED_IN_COOKIE,并且允许开发者通过 secure_logged_in_cookie 过滤器来修改 $secure 的值。

  5. 生成 Cookie 值:

    $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme );
    $scheme_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, 'token' );

    wp_generate_auth_cookie() 函数用于生成 Cookie 的值。 这个函数会根据用户 ID、过期时间和方案生成一个加密的字符串。 咱们后面会详细讲这个函数。 生成了两个cookie,一个auth_cookie,一个scheme_cookie。

  6. 设置 Cookie:

    setcookie( $auth_cookie_name, $auth_cookie, $expiration, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
    setcookie( $scheme_cookie_name, $scheme_cookie, $expiration, COOKIEPATH, COOKIE_DOMAIN, $secure, true );

    setcookie() 函数是 PHP 内置的函数,用于设置 Cookie。 咱们来看看它的参数:

    • $auth_cookie_name: Cookie 的名称。
    • $auth_cookie: Cookie 的值。
    • $expiration: Cookie 的过期时间,Unix 时间戳格式。
    • COOKIEPATH: Cookie 的路径,通常是网站的根目录。 WordPress 定义了 COOKIEPATH 常量。
    • COOKIE_DOMAIN: Cookie 的域名,通常是网站的域名。 WordPress 定义了 COOKIE_DOMAIN 常量。
    • $secure: 是否只允许 HTTPS 连接访问 Cookie。 如果为 true,则只有 HTTPS 连接才能访问 Cookie。
    • true: httponly 标志。 如果为 true,则 JavaScript 无法访问 Cookie,可以防止 XSS 攻击。

    所以,这行代码的意思就是:设置一个名为 $auth_cookie_name 的 Cookie,值为 $auth_cookie,过期时间为 $expiration,路径为 COOKIEPATH,域名为 COOKIE_DOMAIN,只允许 HTTPS 连接访问(如果 $securetrue),并且 JavaScript 无法访问。

    同理,第二行代码设置了scheme cookie。

  7. 设置 "wp-saving-post" Cookie (如果需要 "记住我"):

    if ( $remember ) {
       setcookie( 'wp-saving-post', 'checking', time() + 30, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true );
    }

    如果设置了 "记住我" 功能,这段代码会设置一个名为 wp-saving-post 的 Cookie。 这个 Cookie 的作用是防止用户在编辑文章时丢失数据。 它的过期时间是 30 秒,路径是 ADMIN_COOKIE_PATH,也就是 WordPress 后台的路径。

  8. 触发 set_auth_cookie 动作:

    do_action( 'set_auth_cookie', $user_id, $remember, $expiration, $scheme );

    do_action() 函数是 WordPress 的动作钩子函数,用于触发一个动作。 这里的动作是 set_auth_cookie,允许开发者在设置 Cookie 之后执行一些自定义的操作。

    参数 说明
    set_auth_cookie 动作名称
    $user_id 用户 ID
    $remember 是否“记住我”
    $expiration Cookie 的过期时间,Unix 时间戳格式
    $scheme Cookie 的方案

四、wp_generate_auth_cookie() 函数: Cookie 值的“加密大师”

咱们再来看看 wp_generate_auth_cookie() 函数,它是如何生成 Cookie 值的。

/**
 * Generates an authentication cookie.
 *
 * @since 2.6.0
 *
 * @param int    $user_id     User ID.
 * @param int    $expiration  Unix timestamp for when the cookie expires.
 * @param string $scheme      Authentication scheme. Default is 'auth'. Accepts 'auth', 'secure_auth', or 'logged_in'.
 * @param string $token_type  Optional. Type of token to generate. Accepts 'auth' or 'token'. Default is 'auth'.
 * @return string Authentication cookie.
 */
function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token_type = 'auth' ) {
    $key = wp_hash( $user_id . '|' . $expiration . '|' . $scheme . '|' . $token_type, $scheme );
    $hash = hash_hmac( 'md5', $user_id . '|' . $expiration . '|' . $scheme . '|' . $token_type, $key );
    $cookie = $user_id . '|' . $expiration . '|' . $hash;

    return $cookie;
}
  1. 生成 Key:

    $key = wp_hash( $user_id . '|' . $expiration . '|' . $scheme . '|' . $token_type, $scheme );

    wp_hash() 函数用于生成一个唯一的 Key。 它的第一个参数是一个字符串,由用户 ID、过期时间、方案和token类型拼接而成。 第二个参数是方案,用于确定使用哪个盐值。

  2. 生成 Hash:

    $hash = hash_hmac( 'md5', $user_id . '|' . $expiration . '|' . $scheme . '|' . $token_type, $key );

    hash_hmac() 函数用于生成一个 HMAC (Hash-based Message Authentication Code)。 它的第一个参数是哈希算法,这里是 md5。 第二个参数是消息,也就是用户 ID、过期时间和方案拼接成的字符串。 第三个参数是 Key,也就是上一步生成的 Key。

    HMAC 是一种消息认证码算法,可以防止消息被篡改。

  3. 拼接 Cookie 值:

    $cookie = $user_id . '|' . $expiration . '|' . $hash;

    最后,将用户 ID、过期时间和 Hash 拼接成一个字符串,作为 Cookie 的值。

五、总结:wp_set_auth_cookie() 的工作流程

咱们来总结一下 wp_set_auth_cookie() 函数的工作流程:

  1. 接收用户 ID、是否“记住我”、过期时间和方案等参数。
  2. 根据是否是 HTTPS 连接,设置 $secure 变量。
  3. 根据 $remember 的值,设置 Cookie 的过期时间。
  4. 根据 $scheme 的值,确定 Cookie 的名称。
  5. 调用 wp_generate_auth_cookie() 函数生成 Cookie 的值。
  6. 调用 setcookie() 函数设置 Cookie。
  7. 如果需要“记住我”,设置 wp-saving-post Cookie。
  8. 触发 set_auth_cookie 动作。

六、安全性考量

WordPress 的 Cookie 安全性设计还是比较严谨的,主要体现在以下几个方面:

  1. HTTPS 支持: 通过 $secure 标志,可以确保 Cookie 只能在 HTTPS 连接中传输,防止被窃听。
  2. httponly 标志: 通过 httponly 标志,可以防止 JavaScript 访问 Cookie,防止 XSS 攻击。
  3. HMAC 算法: 通过 HMAC 算法,可以防止 Cookie 被篡改。
  4. 盐值: 通过盐值,可以增加 Cookie 的破解难度。

七、代码演示: 如何使用 wp_set_auth_cookie()

// 假设用户登录验证成功
$user_id = 123; // 用户 ID
$remember = true; // 记住我

// 设置验证 Cookie
wp_set_auth_cookie( $user_id, $remember );

// 重定向到首页
wp_redirect( home_url() );
exit;

这段代码演示了如何使用 wp_set_auth_cookie() 函数来设置验证 Cookie。 首先,假设用户登录验证成功,获取到用户 ID。 然后,设置 $remember 变量为 true,表示要“记住我”。 最后,调用 wp_set_auth_cookie() 函数设置 Cookie,并重定向到首页。

八、wp_clear_auth_cookie() 函数:告别 Cookie

wp_set_auth_cookie() 相对应,WordPress 提供了 wp_clear_auth_cookie() 函数来清除验证 Cookie,也就是用户登出。

/**
 * Clears the authentication cookies.
 *
 * @since 2.5.0
 */
function wp_clear_auth_cookie() {
    /**
     * Fires before the authentication cookies are cleared.
     *
     * @since 3.0.0
     *
     * @param string $scheme The scheme to use. Default is 'auth'.
     */
    do_action( 'clear_auth_cookie', 'auth' );

    _wp_clear_auth_cookie();
}

可以看到,它调用了 _wp_clear_auth_cookie() 函数来完成实际的清除工作,并触发了 clear_auth_cookie 动作。

/**
 * Clears all authentication cookies.
 *
 * @access private
 * @since 3.5.0
 */
function _wp_clear_auth_cookie() {
    $secure = is_ssl();

    setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
    setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, true, true );
    setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
    setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN, $secure, true );
    setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN, true, true );
    setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN, $secure, true );
}

_wp_clear_auth_cookie() 函数的原理很简单,就是将所有可能的验证 Cookie 的值设置为空,并将过期时间设置为过去的时间,从而使浏览器删除这些 Cookie。 它不仅清除了普通的 Cookie,还清除了 Secure Cookie 和 Logged-in Cookie,并且考虑到了 Cookie 路径的问题,分别在 COOKIEPATHSITECOOKIEPATH 下都进行了清除操作。

九、总结的总结:Cookie 是 WordPress 登录验证的基石

总而言之,wp_set_auth_cookie() 函数是 WordPress 登录验证的核心,它通过设置 Cookie 来实现用户登录状态的保持。 理解了这个函数的工作原理,就能更好地理解 WordPress 的用户验证机制,也能更好地保护网站的安全。 希望今天的讲解对大家有所帮助!

感谢各位观众老爷的捧场! 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注