搜索全站
安全防护 9 分钟阅读

WordPress 用户角色与权限详解:五种默认角色与自定义角色

编辑看不到插件菜单、作者上传不了图片、客户误删了主题文件——都是权限没配对。本文讲清 WordPress 五种默认角色的能力边界、capabilities 机制、用代码和插件自定义角色的做法,以及权限失控的三个真实案例。

U
UFO_PF 2018-09-05 · 阅读 9 分钟
Wo 安全防护
阅读提示
本文约 3,544 字,预计阅读 9 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:把管理员账号给客户,是灾难的开始

最常见的场景:站做好了,客户要自己发文章,于是直接把管理员账号给他。三个月后,客户装了个来路不明的”SEO 优化”插件,站点被挂黑链;或者客户在外观 → 主题文件编辑器里改了一行 PHP,前台全白。

这类事故的根因不是客户乱来,而是权限给多了。WordPress 自带的角色体系本来就能精确控制,只是大部分人没用过。

原理分析:角色与能力是两层

WordPress 权限模型分两层,容易混淆:

  • 能力(Capability):最小的权限单位,是一堆字符串常量,比如 edit_posts、publish_posts、install_plugins、edit_theme_options、manage_options。
  • 角色(Role):能力的一个集合,比如”作者”这个角色包含 edit_posts、publish_posts、upload_files 等若干能力。

一个用户只能有一个角色(默认单站点),但可以额外附加若干能力。判断权限时永远判断能力,不判断角色:

if ( current_user_can( 'manage_options' ) ) {
    // ...
}

这个细节很重要:很多插件只判断 manage_options,所以你就算建了个叫”超级编辑”的角色,只要它不含 manage_options,插件菜单照样不显示。这也是”我明明给了权限但菜单看不到”的根本原因。

五种默认角色的能力边界:

角色 写文章 发布文章 上传文件 编辑他人文章 管理评论 装插件/主题 改站点设置
订阅者 ✗ ✗ ✗ ✗ ✗ ✗ ✗
投稿者 ✓ ✗ ✓ ✗ ✗ ✗ ✗
作者 ✓ ✓ ✓ ✗ ✗ ✗ ✗
编辑 ✓ ✓ ✓ ✓ ✓ ✗ ✗
管理员 ✓ ✓ ✓ ✓ ✓ ✓ ✓

多站点还多一个超级管理员(Super Admin),能管理整个网络、装主题插件、增删站点。

保姆级实操

场景一:给编辑开放插件菜单权限(不推荐但常见需求)

// 主题 functions.php 或小型功能插件
add_action( 'admin_init', function() {
    $role = get_role( 'editor' );
    if ( $role && ! $role->has_cap( 'manage_options' ) ) {
        $role->add_cap( 'manage_options' );
    }
});

警告:manage_options 等于把整个设置页交出去,包括站点地址、讨论设置、甚至部分插件的敏感配置。更安全的做法是只加 install_plugins 或 activate_plugins,并且最好只加 update_plugins。

场景二:新建一个”SEO 专员”角色

add_action( 'init', function() {
    add_role( 'seo_manager', 'SEO 专员', array(
        'read'                 => true,
        'edit_posts'           => true,
        'edit_others_posts'    => true,
        'edit_published_posts' => true,
        'publish_posts'        => true,
        'upload_files'         => true,
        'manage_categories'    => true,
        'edit_files'           => false,   // 明确不给主题文件编辑权
    ));
});

add_role() 写进数据库,只在第一次生效。改能力数组后再跑不会更新,必须先 remove_role( 'seo_manager' ) 再 add_role()。这个”改了代码没反应”的问题非常常见。

场景三:精细控制——编辑能改菜单但不能改主题

add_action( 'admin_init', function() {
    $role = get_role( 'editor' );
    $role->add_cap( 'edit_theme_options' );   // 能看到外观菜单
    // 再把主题文件编辑器关掉
});

// 全局关闭主题/插件文件编辑器
define( 'DISALLOW_FILE_EDIT', true );

DISALLOW_FILE_EDIT 加到 wp-config.php 里,后台外观和插件菜单里就不再有”文件编辑器”。这是安全防护里性价比最高的一条,建议所有站点都加。

场景四:让作者能上传文件但看不到媒体库里别人的图

WordPress 默认媒体库对所有能 upload_files 的用户开放,看不到别人的图要额外处理:

add_filter( 'ajax_query_attachments_args', function( $query ) {
    $user = wp_get_current_user();
    if ( ! in_array( 'administrator', $user->roles, true )
         && ! in_array( 'editor', $user->roles, true ) ) {
        $query['author'] = $user->ID;
    }
    return $query;
});

场景五:临时提权后回收

有时候插件要求管理员才能配置,可以给编辑临时加 manage_options,配置完再撤:

# 通过 WP-CLI 查看当前角色能力
wp role list
wp cap list editor

常见踩坑与失败案例

  1. 案例一:某站给编辑加了 manage_options,结果编辑在设置里把”站点地址”改错了,全站 301 到错误域名,百度快照全掉。教训:不要用 manage_options 当”万能钥匙”。
  2. add_role 改代码不生效:上面说过,角色存数据库,改了要删了重建。开发时建议配合 wp cap add/remove 命令行直接改:

bash
wp cap add editor edit_theme_options
wp cap remove editor manage_options

  1. 案例二:客户用管理员账号装了个”WordPress 优化”插件,插件里带了后门,站点被用来发垃圾外链。正确做法是客户只给”编辑”角色,装插件由建站方负责。
  2. 案例三:某多语言站给编辑加了 edit_users,结果编辑把管理员降成了订阅者,把自己锁在门外。这种只能进数据库改 wp_usermeta 的 wp_capabilities 恢复:

sql
UPDATE wp_usermeta SET meta_value = 'a:1:{s:13:"administrator";b:1;}'
WHERE user_id = 1 AND meta_key = 'wp_capabilities';

注意表前缀和 meta_key 前缀(多站点是 wp_2_capabilities)。

  1. 自定义文章类型的能力:注册 CPT 时如果用了 capability_type => 'post',那编辑能管;用了自定义的 capability_type => 'product',则默认只有管理员有权限,编辑看不到。需要显式给角色加 edit_products、publish_products 等能力。

总结

权限配置的三个原则:最小权限(客户通常给”编辑”就够,投稿团队给”作者”)、永不外借管理员(要装插件就自己装)、关掉文件编辑器(DISALLOW_FILE_EDIT)。技术上记住”判断能力不判断角色”这条铁律,几乎所有”菜单不显示”的问题都能从这里找到答案。角色改动建议用 wp cap 命令行即时生效,别反复改代码重启。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。