为什么需要「阅读权限」
一个内容站点要走向付费或私密分发,光靠「整站公开」是不够的:有些文章想卖单篇,有些只给订阅用户看,有些只发一个密码给特定读者,还有些要设开放时间。这些诉求在 Halo 原生能力里并没有统一入口。
于是我们做了一个 Halo 2.x 插件,把这些访问控制收敛到一个地方:全线阅读权限。它的核心原则是——权限判断放在服务端,而不是前端遮罩。
支持哪些访问控制
- 公开阅读(默认)
- 登录后阅读
- 密码阅读(BCrypt 哈希,不存明文)
- 单篇购买后阅读
- 有效订阅后阅读
- 指定角色 / 用户组阅读
- 指定用户白名单阅读
- 时间窗口(定时开放、到期关闭)
- 多条件组合(满足任一 / 满足全部)
- 免费预览比例,或手动
<!--reading-preview-->分隔线
服务端保护,而不是前端遮罩
很多「付费阅读」实现只在页面用 CSS 或 JS 把正文藏起来,但正文仍然存在于 HTML 源码和接口返回里,懂一点技术就能绕过。这个插件选择了更彻底的做法:
- 正文拦截:通过 Halo 的内容处理扩展点,在服务端渲染前就把受保护正文替换成解锁组件,页面源码里根本没有完整正文。
- 授权接口:解锁、读取全文走独立的授权接口,只有通过密码 / 登录 / 权益校验后才返回完整正文。
- 管理员与作者放行:站点管理员和文章作者自动可见全文,不影响日常编辑预览。
使用方法
第一步:在文章编辑器里打开权限设置
进入 Halo 控制台的「文章 → 编辑」,在默认编辑器的顶部工具栏会多出一个「阅读权限」按钮。点击后会在新标签页打开规则配置页,并自动带入当前文章,无需手动填写文章内部名称。
第二步:选择访问模式并保存
在规则配置页选择访问模式:公开、登录后、密码、单篇付费、订阅、用户组、白名单或时间窗口;需要密码的填阅读密码(只保存 BCrypt 哈希),需要付费的填价格,需要时间限制的填开放/关闭时间,然后保存。
第三步:读者访问时完成验证
读者打开该文章时,正文会被服务端替换成解锁组件,页面源码不含完整正文。读者通过输入密码、登录、或满足权益后,才能在页面内继续阅读全文。

实现要点
- 权限决策引擎:规则以扩展资源(AccessRule)持久化,支持 ANY / ALL 组合,逐条评估后合并结果。
- RBAC 角色模板:公开接口聚合到 anonymous 角色,管理接口聚合到 super-role,符合 Halo 2.x 的授权模型。
- 编辑器扩展点:通过
default:editor:extension:create扩展点,在默认编辑器工具栏注入「阅读权限」按钮。 - 反向代理静态资源:前台解锁组件的 JS / CSS 通过插件的 ReverseProxy 声明暴露,主题无需改动即可加载。
- 密码安全:密码只保存 BCrypt 哈希,校验用
matches(),绝不落明文。
已真实验证的功能
| 场景 | 预期 | 实测 |
|---|---|---|
| 密码文章 · 错误密码 | 拒绝 | ✅ 403 password-required |
| 密码文章 · 正确密码 | 返回全文 | ✅ 200 |
| 登录文章 · 匿名访问 | 拒绝 | ✅ 403 login-required |
| 白名单 · 非白名单用户 | 拒绝 | ✅ 403 not-allowed |
| 时间窗口 · 未到开放时间 | 拒绝 | ✅ 403 outside-time-window |
| 受保护文章正文 | 页面不含完整正文 | ✅ 已确认只渲染解锁组件 |
已知限制与下一步
需要如实说明:当前版本聚焦「访问控制」本身,支付通道(微信 / 支付宝)尚未接入,购买 / 订阅目前是权益数据模型 + 适配层,等待接入商户参数;另外 Halo 的自动摘要若来自全文,作者需手动把摘要设置为预览文本,插件下一版会加入摘要自动截断。
下一步:接入支付回调、自动处理摘要、补充后台规则编辑体验,然后走应用市场发布流程。
评论