大家好!欢迎来到今天的 WordPress 内幕小课堂。今天咱们来扒一扒 WordPress 中鼎鼎大名的 is_user_logged_in()
函数的底裤,看看它究竟是怎么判断用户是不是已经登录的。
开场白:登录状态的那些事儿
话说江湖上行走,身份很重要。在 WordPress 这个虚拟世界里,登录状态就代表着你的身份。你是游客,只能看看热闹;你是会员,可以发表评论;你是管理员,那就呼风唤雨,掌控一切。
那么,WordPress 怎么知道你是谁呢?靠的就是这个 is_user_logged_in()
函数。它就像一个门卫,检查你有没有“通行证”,也就是有没有登录。
第一步:全局变量的侦查
is_user_logged_in()
函数的第一反应,不是直接去翻你的 Cookie,而是先看看有没有什么全局变量已经告诉你答案了。
function is_user_logged_in() {
global $current_user;
if ( ! isset( $current_user ) ) {
return false;
}
return ( $current_user instanceof WP_User && $current_user->ID > 0 );
}
这段代码看起来是不是很简单?咱们来一句一句地解读:
-
global $current_user;
:这句的意思是,把$current_user
这个全局变量引入到当前函数的作用域里来。$current_user
是 WordPress 用来保存当前用户信息的,如果用户登录了,它就会被赋值为一个WP_User
对象。 -
if ( ! isset( $current_user ) ) { return false; }
:这句判断$current_user
变量是否存在。如果不存在,说明 WordPress 还没初始化用户,那肯定没登录,直接返回false
。 -
return ( $current_user instanceof WP_User && $current_user->ID > 0 );
:这句是关键。它做了两件事:$current_user instanceof WP_User
:判断$current_user
是不是一个WP_User
类的实例。只有登录用户才会被赋值为WP_User
对象。$current_user->ID > 0
:判断$current_user
对象的ID
属性是否大于 0。ID
属性代表用户的 ID,只有登录用户才有有效的 ID(大于 0)。
如果这两个条件都满足,说明用户已经登录,返回
true
。否则,返回false
。
为什么要先检查全局变量?
你可能会问,为什么不直接去检查 Cookie 呢?原因很简单:效率!
如果每次都要解析 Cookie,那会消耗不少资源。而全局变量是已经加载到内存中的,访问速度快得多。所以,WordPress 先检查全局变量,如果全局变量已经有了用户信息,那就直接返回结果,省去了解析 Cookie 的麻烦。
第二步:Cookie 大作战
如果全局变量 $current_user
不存在,或者不是一个有效的 WP_User
对象,那就说明 WordPress 还没初始化用户,或者用户没有登录。这时候,is_user_logged_in()
函数就无能为力了,它只能返回 false
。
但是,真正负责设置 $current_user
的函数是 wp_get_current_user()
,它才是真正和 Cookie 打交道的幕后英雄。让我们来深入了解一下 wp_get_current_user()
的工作原理。
function wp_get_current_user() {
global $current_user, $wp_roles;
if ( ! ( $current_user instanceof WP_User ) ) {
wp_set_current_user();
}
return $current_user;
}
这段代码的核心在于 wp_set_current_user()
函数。如果 $current_user
不是一个 WP_User
对象,wp_get_current_user()
就会调用 wp_set_current_user()
来尝试设置 $current_user
。
接下来,咱们就要深入到 wp_set_current_user()
函数的内部,看看它是如何利用 Cookie 来判断用户是否登录的。
wp_set_current_user()
的秘密
wp_set_current_user()
函数的逻辑比较复杂,它会根据不同的情况采取不同的策略。
function wp_set_current_user( $id = 0, $name = '' ) {
global $current_user, $wpdb;
if ( ! ( $current_user instanceof WP_User ) ) {
$current_user = new WP_User( $id, $name );
}
if ( ! $id ) {
$id = apply_filters( 'determine_current_user', false );
}
if ( ! $id ) {
if ( ! empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
$logged_in_cookie = $_COOKIE[ LOGGED_IN_COOKIE ];
$cookie_elements = wp_parse_auth_cookie( $logged_in_cookie, 'logged_in' );
if ( ! empty( $cookie_elements ) ) {
$username = $cookie_elements['username'];
$expiration = $cookie_elements['expiration'];
$token = $cookie_elements['token'];
if ( $expiration > time() ) {
$user = get_user_by( 'login', $username );
if ( $user && wp_validate_auth_cookie( $logged_in_cookie, 'logged_in', $user ) ) {
$id = $user->ID;
}
}
}
} elseif ( ! empty( $_COOKIE[ SECURE_AUTH_COOKIE ] ) ) {
// Secure Auth Cookie logic (for HTTPS) - similar to LOGGED_IN_COOKIE
$secure_auth_cookie = $_COOKIE[ SECURE_AUTH_COOKIE ];
$cookie_elements = wp_parse_auth_cookie( $secure_auth_cookie, 'secure_auth' );
if ( ! empty( $cookie_elements ) ) {
$username = $cookie_elements['username'];
$expiration = $cookie_elements['expiration'];
$token = $cookie_elements['token'];
if ( $expiration > time() ) {
$user = get_user_by( 'login', $username );
if ( $user && wp_validate_auth_cookie( $secure_auth_cookie, 'secure_auth', $user ) ) {
$id = $user->ID;
}
}
}
} elseif ( ! empty( $_COOKIE[ AUTH_COOKIE ] ) ) {
// Auth Cookie logic - similar to LOGGED_IN_COOKIE
$auth_cookie = $_COOKIE[ AUTH_COOKIE ];
$cookie_elements = wp_parse_auth_cookie( $auth_cookie, '' ); //Empty string for default auth cookie
if ( ! empty( $cookie_elements ) ) {
$username = $cookie_elements['username'];
$expiration = $cookie_elements['expiration'];
$token = $cookie_elements['token'];
if ( $expiration > time() ) {
$user = get_user_by( 'login', $username );
if ( $user && wp_validate_auth_cookie( $auth_cookie, '', $user ) ) {
$id = $user->ID;
}
}
}
}
}
if ( $id ) {
$current_user = new WP_User( $id );
} else {
$current_user = wp_get_anonymous_user();
}
do_action( 'set_current_user', $current_user, $id );
}
这段代码看着有点长,但其实逻辑还是比较清晰的。咱们一步一步来分析:
-
初始化
$current_user
if ( ! ( $current_user instanceof WP_User ) ) { $current_user = new WP_User( $id, $name ); }
如果
$current_user
还不是一个WP_User
对象,就创建一个新的WP_User
对象。如果传入了$id
和$name
参数,就用它们来初始化这个对象。 -
determine_current_user
过滤器if ( ! $id ) { $id = apply_filters( 'determine_current_user', false ); }
这是一个非常重要的过滤器。它允许插件或主题通过自定义逻辑来设置当前用户 ID。如果插件或主题已经设置了用户 ID,那就直接使用它。
-
Cookie 检查
如果
$id
仍然是空的,那就开始检查 Cookie。WordPress 会检查三种 Cookie:LOGGED_IN_COOKIE
:用于普通登录的 Cookie。SECURE_AUTH_COOKIE
:用于 HTTPS 安全登录的 Cookie。AUTH_COOKIE
:用于管理后台登录的 Cookie。
对于每种 Cookie,WordPress 都会做以下事情:
- 检查 Cookie 是否存在:如果 Cookie 不存在,那就跳过。
- 解析 Cookie:使用
wp_parse_auth_cookie()
函数来解析 Cookie,提取用户名、过期时间和 Token。 - 验证 Cookie:
- 检查 Cookie 是否过期。
- 根据用户名获取用户对象。
- 使用
wp_validate_auth_cookie()
函数来验证 Cookie 的有效性。这个函数会检查 Cookie 中的 Token 是否和数据库中存储的 Token 匹配。
如果 Cookie 验证成功,就获取用户的 ID,并将其赋值给
$id
变量。 -
设置
$current_user
if ( $id ) { $current_user = new WP_User( $id ); } else { $current_user = wp_get_anonymous_user(); }
如果
$id
变量有值,说明找到了登录用户,就创建一个新的WP_User
对象,并将其赋值给$current_user
。如果$id
变量仍然是空的,说明没有找到登录用户,就调用wp_get_anonymous_user()
函数来获取一个匿名用户对象,并将其赋值给$current_user
。 -
set_current_user
动作do_action( 'set_current_user', $current_user, $id );
这是一个动作钩子,允许插件或主题在设置当前用户之后执行一些自定义操作。
Cookie 的结构
咱们再来仔细看看 wp_parse_auth_cookie()
函数是如何解析 Cookie 的。WordPress 的登录 Cookie 并不是简单的用户名和密码,而是一个加密的字符串。这个字符串包含了以下信息:
字段 | 描述 |
---|---|
username |
用户名 |
expiration |
Cookie 的过期时间戳 |
token |
用于验证 Cookie 有效性的 Token |
wp_parse_auth_cookie()
函数会将这个加密的字符串解密,提取出这些信息,然后交给 wp_validate_auth_cookie()
函数进行验证。
wp_validate_auth_cookie()
的验证
wp_validate_auth_cookie()
函数会做以下验证:
- 检查 Cookie 是否过期:如果 Cookie 已经过期,那就验证失败。
- 检查 Token 是否匹配:WordPress 会在用户登录时生成一个 Token,并将其存储在数据库中。
wp_validate_auth_cookie()
函数会从 Cookie 中提取 Token,然后和数据库中存储的 Token 进行比较。如果 Token 不匹配,那就验证失败。
总结
咱们来总结一下 is_user_logged_in()
函数的判断流程:
- 检查全局变量
$current_user
是否存在,并且是否是一个有效的WP_User
对象。如果是,则返回true
。 - 如果全局变量
$current_user
不存在或者不是一个有效的WP_User
对象,则调用wp_get_current_user()
函数。 wp_get_current_user()
函数会调用wp_set_current_user()
函数来设置$current_user
。wp_set_current_user()
函数会依次检查determine_current_user
过滤器和 Cookie,尝试获取用户 ID。- 如果找到了用户 ID,就创建一个新的
WP_User
对象,并将其赋值给$current_user
。 - 如果没找到用户 ID,就创建一个匿名用户对象,并将其赋值给
$current_user
。 is_user_logged_in()
函数最终会根据$current_user
对象的状态来判断用户是否登录。
一些有用的函数
除了 is_user_logged_in()
、wp_get_current_user()
和 wp_set_current_user()
之外,还有一些其他的函数也和登录状态有关,比如:
wp_login()
:用户登录函数。wp_logout()
:用户登出函数。wp_get_current_user()
: 获取当前用户信息。get_current_user_id()
:获取当前用户的 ID。
最后的话
希望今天的课程能让你对 WordPress 的登录机制有更深入的了解。记住,理解这些底层的原理,才能更好地开发 WordPress 插件和主题。
下次再见!