好吧,各位听众,今天咱们就来扒一扒 WordPress 权限系统里那个至关重要的函数:current_user_can()
。 这家伙可是个“保安”,负责检查当前用户是不是有资格做某些事情,比如发帖子、编辑用户、安装插件等等。 咱们要深入源码,看看它到底是怎么运作的,让大家以后都能像驾驭自己的老伙计一样驾驭它。
开场白:权限的重要性
想象一下,你家小区没保安,那岂不是谁都能进进出出?WordPress 也是一样。如果没有权限系统,随便一个游客都能删除你的文章,甚至把你的网站搞瘫痪,那还得了? 所以,权限系统是安全的基础,而 current_user_can()
就是这个安全体系的关键守门人。
current_user_can()
的基本用法
首先,我们先熟悉一下 current_user_can()
的基本用法。这个函数接受一个或多个参数,第一个参数是要检查的权限(capability),后面的参数是可选的,可以用来传递一些上下文信息。
if ( current_user_can( 'edit_posts' ) ) {
// 当前用户有编辑文章的权限,可以执行某些操作
echo '你拥有编辑文章的权限!';
} else {
echo '抱歉,你没有编辑文章的权限。';
}
这里 'edit_posts'
就是一个 capability。 WordPress 内置了很多 capability,比如 'publish_posts'
(发布文章)、'delete_posts'
(删除文章)、'manage_options'
(管理选项)等等。 你也可以自定义 capability,让你的插件或主题更加灵活。
深入源码:current_user_can()
的真面目
现在,让我们一起跳进 current_user_can()
的源码里,看看它到底是怎么工作的。 在 WordPress 的 pluggable.php
文件中,你会找到这个函数的定义:
function current_user_can( $capability ) {
$args = array_slice( func_get_args(), 1 );
return apply_filters( 'current_user_can', get_current_user_id() ? user_can( get_current_user_id(), $capability, ...$args ) : false, $capability, get_current_user_id(), $args );
}
看起来有点吓人,是不是? 别怕,我们一步一步来拆解。
-
$args = array_slice( func_get_args(), 1 );
: 这行代码获取传递给current_user_can()
函数的所有参数,除了第一个参数(capability 本身)。func_get_args()
获取所有参数,array_slice()
从索引 1 开始(也就是第二个参数)提取出一个新的数组,存储在$args
变量中。 这些参数会在后面传递给user_can()
函数,用于更精细的权限检查。 -
get_current_user_id()
: 这个函数获取当前用户的 ID。 如果用户未登录,它会返回 0。 -
user_can( get_current_user_id(), $capability, ...$args )
: 这才是权限检查的核心!user_can()
函数负责判断用户是否拥有指定的 capability。 它接收用户 ID、capability 和额外的参数($args
)作为输入。...$args
是 PHP 的“解包”操作符,它会将$args
数组中的元素展开,作为user_can()
函数的单独参数传递进去。 -
apply_filters( 'current_user_can', ... )
: 这是一个 WordPress 的过滤器(filter)。 它允许你通过插件或主题来修改current_user_can()
的返回值。 也就是说,你可以自定义权限检查的逻辑,覆盖 WordPress 默认的行为。- 第一个参数
'current_user_can'
是过滤器的名称。 - 第二个参数是
user_can()
的返回值(true
或false
),也就是默认的权限判断结果。 - 后面的参数
$capability
,get_current_user_id()
,$args
会被传递给过滤器函数,方便你进行更复杂的权限检查。
- 第一个参数
-
get_current_user_id() ? ... : false
: 这是一个三元运算符。 如果get_current_user_id()
返回一个非零值(表示用户已登录),则执行user_can()
函数并返回其结果;否则(用户未登录),直接返回false
,表示用户没有权限。
user_can()
函数的奥秘
current_user_can()
本身只是个“门卫”,真正的权限检查是由 user_can()
完成的。 user_can()
的定义在 wp-includes/capabilities.php
文件中。
function user_can( $user, $capability ) {
$args = array_slice( func_get_args(), 2 );
return call_user_func_array( array( wp_roles(), 'user_has_cap' ), array_merge( array( $user, $capability ), $args ) );
}
让我们来分析一下这段代码:
-
$args = array_slice( func_get_args(), 2 );
: 和current_user_can()
类似,这行代码获取传递给user_can()
函数的所有参数,除了前两个参数(用户 ID 和 capability 本身)。 -
call_user_func_array( array( wp_roles(), 'user_has_cap' ), array_merge( array( $user, $capability ), $args ) )
: 这行代码比较复杂,它使用了call_user_func_array()
函数来动态调用WP_Roles
类的user_has_cap()
方法。wp_roles()
返回全局的WP_Roles
对象,这个对象负责管理 WordPress 的角色和权限。array( wp_roles(), 'user_has_cap' )
创建了一个数组,包含了要调用的对象(wp_roles()
)和方法名('user_has_cap'
)。array_merge( array( $user, $capability ), $args )
将用户 ID、capability 和额外的参数合并成一个数组,作为user_has_cap()
方法的参数。call_user_func_array()
使用合并后的参数数组来调用user_has_cap()
方法,并返回其结果。
WP_Roles::user_has_cap()
:终极裁判
现在,我们终于来到了权限检查的最后一站:WP_Roles::user_has_cap()
。 这个方法才是真正的“终极裁判”,它会根据用户的角色和权限配置,判断用户是否拥有指定的 capability。 这个方法同样在 wp-includes/capabilities.php
文件中。 由于代码较长,我们只提取关键部分进行分析。
public function user_has_cap( $user_id, $cap, ...$args ) {
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
if ( 'administrator' === $user->user_login ) { // 仅供演示,实际情况不应直接使用用户名判断
$user = new WP_User( $user_id );
if ( in_array( 'administrator', $user->roles ) ) {
return true;
}
}
$caps = $this->get_user_caps( $user );
if ( empty( $caps ) ) {
return false;
}
if ( in_array( 'do_not_allow', $caps, true ) ) {
return false;
}
if ( isset( $caps[$cap] ) ) {
$check = $caps[$cap];
} else {
$check = false;
}
/**
* Filters whether a user has the specified capability.
*
* @since 2.8.0
*
* @param bool $check Whether the user has the capability. Default false.
* @param string $cap Capability name.
* @param int $user_id The user ID.
* @param array $args Adds the context to the cap check, which might change
* the result.
*/
return apply_filters( 'user_has_cap', $check, $cap, $user_id, $args );
}
-
$user = get_userdata( $user_id );
: 根据用户 ID 获取用户数据。 如果用户不存在,返回false
。 -
if ( 'administrator' === $user->user_login ) { ... }
: 这是一个不推荐的做法,仅作演示! 这个代码片段用于快速判断用户是否是管理员。 强烈建议不要直接使用用户名进行权限判断,这很不安全! 更好的做法是检查用户是否拥有administrator
角色。 -
$caps = $this->get_user_caps( $user );
: 获取用户的所有 capability。get_user_caps()
方法会根据用户的角色,将所有相关的 capability 收集到一个数组中。 -
if ( empty( $caps ) ) { return false; }
和if ( in_array( 'do_not_allow', $caps, true ) { return false; }
: 如果用户没有任何 capability,或者拥有一个特殊的'do_not_allow'
capability,则表示用户没有权限。 -
if ( isset( $caps[$cap] ) ) { $check = $caps[$cap]; } else { $check = false; }
: 检查用户的 capability 数组中是否包含指定的$cap
。 如果包含,则$check
为true
;否则,$check
为false
。 -
return apply_filters( 'user_has_cap', $check, $cap, $user_id, $args );
: 又是一个过滤器! 允许你通过插件或主题来修改user_has_cap()
的返回值,提供更灵活的权限控制。
总结:权限检查的完整流程
现在,我们来总结一下 current_user_can()
函数的完整工作流程:
current_user_can()
接收 capability 和可选的参数。current_user_can()
获取当前用户 ID。current_user_can()
调用user_can()
函数,并将用户 ID、capability 和参数传递给它。user_can()
函数调用WP_Roles::user_has_cap()
方法。WP_Roles::user_has_cap()
获取用户的所有 capability。WP_Roles::user_has_cap()
检查用户的 capability 数组中是否包含指定的 capability。WP_Roles::user_has_cap()
返回检查结果(true
或false
)。current_user_can()
和user_has_cap
分别应用过滤器,允许修改检查结果。current_user_can()
返回最终的检查结果。
表格:WordPress 角色和默认 Capability
为了方便大家理解,我整理了一个表格,列出了 WordPress 默认的角色和一些常见的 capability:
角色 | 默认 Capability |
---|---|
Administrator | 所有 Capability (manage_options, install_plugins, delete_users, 等等) |
Editor | publish_posts, edit_posts, delete_posts, manage_categories, moderate_comments, upload_files, 等等 |
Author | publish_posts, edit_posts, delete_posts, upload_files |
Contributor | edit_posts, upload_files |
Subscriber | read |
自定义 Capability
除了使用 WordPress 内置的 capability,你还可以自定义 capability,让你的插件或主题更加灵活。 要自定义 capability,你需要使用 add_role()
或 get_role()
函数来添加或修改角色,并使用 add_cap()
方法来给角色添加 capability。
// 创建一个新的角色 "book_editor"
add_role(
'book_editor',
'Book Editor',
array(
'read' => true, // 允许阅读
'edit_posts' => true, // 允许编辑文章
'publish_posts' => true, // 允许发布文章
'edit_books' => true, // 允许编辑书籍(自定义 capability)
)
);
// 给管理员角色添加 "manage_books" capability
$admin_role = get_role( 'administrator' );
$admin_role->add_cap( 'manage_books' );
// 检查当前用户是否拥有 "edit_books" capability
if ( current_user_can( 'edit_books' ) ) {
echo '你拥有编辑书籍的权限!';
}
传递上下文参数
current_user_can()
和 user_can()
允许你传递额外的参数,用于更精细的权限检查。 这些参数可以用来传递一些上下文信息,比如要编辑的文章 ID,或者要删除的用户 ID。
// 检查当前用户是否有权限编辑 ID 为 123 的文章
if ( current_user_can( 'edit_post', 123 ) ) {
echo '你拥有编辑 ID 为 123 的文章的权限!';
}
// 在你的插件或主题中,你可以使用过滤器来处理这些参数
add_filter( 'user_has_cap', 'my_custom_user_has_cap', 10, 4 );
function my_custom_user_has_cap( $check, $cap, $user_id, $args ) {
if ( 'edit_post' === $cap && isset( $args[0] ) ) {
$post_id = $args[0];
// 在这里进行更复杂的权限检查,比如检查用户是否是文章的作者
$post = get_post( $post_id );
$user = wp_get_current_user();
if ( $post->post_author == $user->ID ) {
return true; // 如果用户是文章的作者,则允许编辑
} else {
return false; // 否则,拒绝编辑
}
}
return $check; // 返回默认的检查结果
}
安全建议
- 不要直接使用用户名进行权限判断! 这很不安全,容易被攻击者利用。 应该使用角色或 capability 进行权限判断。
- 避免硬编码 capability! 将 capability 定义为常量,方便修改和维护。
- 使用过滤器来扩展权限系统! WordPress 的过滤器提供了一种灵活的方式来定制权限检查的逻辑。
- 仔细测试你的权限系统! 确保所有权限都按照你的预期工作,防止出现安全漏洞。
总结
current_user_can()
函数是 WordPress 权限系统的核心。 通过深入了解它的源码,我们可以更好地掌握 WordPress 的权限控制机制,为我们的插件和主题提供更安全、更灵活的权限管理。 希望今天的讲解对大家有所帮助! 下次再见!