WP DEVELOP

EP098. “Subscriber 笔记权限与服务端强制私密”

首页 WordPress 开发课程 MY NOTES 前端功能 · EP098
约 9 分钟· #EP098#MY NOTES 前端功能
🔒 登录后可标记已读

给 Subscriber 角色开放创建/编辑/删除自己笔记的权限(复用 EP087 学过的 capability_type + Members 插件角色授权套路),并且解决一个真实的隐私漏洞:note 文章类型开了 show_in_rest,意味着任何人不登录也能访问 REST API 直接读到全站所有用户的笔记内容。解法分两层:先在 WordPress 后台把文章状态设成 private(私有内容默认不出现在公开查询/API 里);但客户端传的 status 值完全不可信(恶意用户可以改自己浏览器里的 JS 把 status 硬改成 publish),所以还要在服务端用 wp_insert_post_data 过滤器强制所有 note 类型文章的状态改成 private客户端传什么都不算数


涉及文件

  • wp-content/mu-plugins/university-post-types.php (修改)
  • 后台 Members → Roles:给 Administrator、Subscriber 授权 Notes 权限(后台操作,无对应代码文件)
  • wp-content/themes/fictional-university-theme/functions.php (修改)

代码实现

mu-plugins/university-post-types.php:给 note 文章类型加独立权限(跟 EP087 处理 event/campus 是同一套路):

// wp-content/mu-plugins/university-post-types.php
// note 文章类型注册参数里新增:
'capability_type' => 'note',
'map_meta_cap' => true,

后台授权:Members → Roles → Administrator,勾选 Notes Tab 下的全部权限;Subscriber 角色勾选这 5 项:publish_notesedit_notesedit_published_notesdelete_notesdelete_published_notes——不勾选 edit_others_notes / delete_others_notes,确保 Subscriber 只能动自己的笔记。

functions.php:服务端强制所有 note 文章的状态为 private(追加在文件末尾):

// wp-content/themes/fictional-university-theme/functions.php

// Force note posts to be private
add_filter('wp_insert_post_data', 'makeNotePrivate');

function makeNotePrivate($data) {
  if($data['post_type'] == 'note' AND $data['post_status'] != 'trash') {
    $data['post_status'] = "private";
  }

  return $data;
}

关键改动点:

  • Subscriber 只授予 5 个权限、刻意不给 edit_others_notes / delete_others_notes——因为默认要「零信任」对待 Subscriber 这类开放注册就能拿到的角色,只给完成功能所需的最小权限集合
  • edit_notes / delete_notes 管的是「草稿」状态的笔记,edit_published_notes / delete_published_notes 管的是「已发布」状态的笔记——note 的笔记后面会被强制成 private 状态而不是 draft,但权限体系里 private 内容依然要满足 edit_published_* 这条权限才能改,所以两组权限都要给,缺一个都会导致某些操作失败
  • wp_insert_post_data 是一个在文章即将写入数据库前触发的过滤器,收到的 $data 是即将保存的全部字段(标题、内容、状态等),函数把它改完再 return,改完的版本才会真正写进数据库——这是比在前端信任 JS 传来的值更可靠的做法,因为浏览器端的任何代码理论上都能被访问者篡改,只有服务端的检查才靠得住
  • 判断条件必须排除 post_status == 'trash' 这个例外——如果不排除,会导致「删除笔记」操作失效:删除笔记本质上是把状态改成 trash,如果这个过滤器把任何 note 的状态都强制改回 private,那么永远没法把它挪进回收站
  • 这个过滤器对所有文章类型的保存都会触发,所以必须先判断 $data['post_type'] == 'note',不然会连博客文章、Program、Professor 这些原本该公开的文章类型也被一起强制成私有

[截图:wp-admin Members 插件 Roles 设置页面,Subscriber 角色勾选的 Notes 相关权限(publish_notes/edit_notes/edit_published_notes/delete_notes/delete_published_notes)]


Hook / Function 速查

名称类型用途
wp_insert_post_dataWP filter hook文章即将写入数据库前触发,可以在这里拦截并修改即将保存的数据

常见坑

  • 只在前端 JavaScript 里把 status 设成 private 就以为万事大吉——客户端的任何值都可能被篡改,隐私/权限相关的强制规则必须在服务端兜底,不能只依赖前端传的数据
  • wp_insert_post_data 过滤器忘记排除 post_status == 'trash' 的情况——会导致这个文章类型永远没法被删除(挪进回收站的动作会被强制改回 private)
  • 只给 Subscriber 授予 edit_notes 而不给 edit_published_notes——note 笔记很快会变成 private 状态,只给「草稿」权限的话用户会发现自己没法编辑已保存的笔记

延伸 / 后续讲座会用到

下一讲(part 2)会继续深挖安全相关的细节。


Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 19, EP098