本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:7月5日复制的资料/用户组权限计划.md。
用户组与权限系统 — 实现计划
目标:增加用户组功能,实现按版块控制浏览、发帖、回复权限
一、现状分析
| 项目 | 当前状态 |
|---|
| 用户角色 | users.role → 'admin' / 'user'(硬编码) |
| 权限控制 | Auth::isAdmin() 判断是否管理员,普通用户无差异 |
| 等级系统 | users.level + points,仅用于展示 badge,不影响权限 |
| 版块 | categories 表,无权限关联 |
二、设计方案
核心思路
用户 → 用户组(手动分配)→ 粗粒度权限:能浏览哪些版块、能否发帖/回复
→ 等级(自动升级) → 细粒度限制:每日发帖上限、附件大小、免验证码
用户组管"能不能做某件事",等级管"能做多少"。两种权限叠加生效——用户先有用户组的发帖权限,才能谈等级带来的"每天能发几帖"。
数据模型
新增表 1:user_groups(用户组)
| 字段 | 类型 | 说明 |
|---|
| id | INT PK | |
| name | VARCHAR(50) | 组名称,如"管理员"、"版主"、"VIP会员"、"普通会员" |
| color | VARCHAR(20) | 组名显示颜色 |
| is_default | TINYINT(1) | 新用户注册时默认分配到此组 |
| created_at | DATETIME | |
新增表 2:category_permissions(版块权限)
| 字段 | 类型 | 说明 |
|---|
| id | INT PK | |
| category_id | INT | 关联 categories.id |
| group_id | INT | 关联 user_groups.id,0 表示未登录用户(游客) |
| can_view | TINYINT(1) | 是否允许浏览该版块 |
| can_post | TINYINT(1) | 是否允许在该版块发新帖 |
| can_reply | TINYINT(1) | 是否允许在该版块回复 |
修改表:users
| 字段 | 变更 | 说明 |
|---|
| role | 保留 | 仍用于 'admin'/'user' 基础区分 |
| group_id | 新增 INT DEFAULT 1 | 关联 user_groups.id |
默认数据
| 用户组 | 说明 |
|---|
| 管理员 | 全部权限,无视版块限制 |
| 版主 | 可管理指定版块 |
| VIP 会员 | 可浏览所有版块、发帖回复 |
| 普通会员 | 可浏览公开版块、发帖回复 |
| 游客 | 仅可浏览公开版块 |
三、涉及文件清单
3.1 数据库
| 文件 | 改动 |
|---|
database/schema.sql | 新增 user_groups、category_permissions 建表语句 |
3.2 新增文件
| 文件 | 说明 |
|---|
app/Helpers/Permission.php | 权限检查核心类(静态方法) |
app/Models/UserGroup.php | 用户组 Model |
app/Models/CategoryPermission.php | 版块权限 Model |
app/Controllers/Admin/UserGroupController.php | 后台用户组管理 |
app/Controllers/Admin/PermissionController.php | 后台版块权限设置 |
app/Views/admin/user_groups.php | 用户组管理页面 |
app/Views/admin/category_permissions.php | 版块权限设置页面 |
3.3 修改文件
| 文件 | 改动 |
|---|
app/Models/User.php | 新增 group_id 字段映射,新增 getGroup() 方法 |
app/Helpers/Auth.php | 新增 getGroupId()、hasPermission() 等 |
app/Helpers/Permission.php | (新文件)权限检查:canView(), canPost(), canReply() |
app/Controllers/ForumController.php | 浏览版块时加权限检查 |
app/Controllers/ThreadController.php | 查看帖子时加权限检查 |
app/Controllers/PostController.php | 发帖/回复时加权限检查 |
app/Controllers/AuthController.php | 注册时分配默认用户组 |
index.php | 注册后台路由 |
app/Views/admin/_sidebar.php | 加导航链接 |
四、实现步骤
第 1 步:建表 + 默认数据(0.5 天)
CREATE TABLE user_groups (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
color VARCHAR(20) DEFAULT '#666',
is_default TINYINT(1) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO user_groups (id, name, color, is_default) VALUES
(1, '普通会员', '#666', 1),
(2, 'VIP会员', '#f39c12', 0),
(3, '版主', '#27ae60', 0),
(4, '管理员', '#e74c3c', 0);
CREATE TABLE category_permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
category_id INT NOT NULL,
group_id INT NOT NULL,
can_view TINYINT(1) DEFAULT 1,
can_post TINYINT(1) DEFAULT 1,
can_reply TINYINT(1) DEFAULT 1,
UNIQUE KEY uk_cat_group (category_id, group_id),
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE users ADD COLUMN group_id INT DEFAULT 1;
第 2 步:Permission Helper(0.5 天)
class Permission
{
// 检查用户是否有权浏览版块
public static function canView($categoryId, $userId = null): bool
// 检查是否有权发帖
public static function canPost($categoryId, $userId = null): bool
// 检查是否有权回复
public static function canReply($threadId, $userId = null): bool
// 获取用户组信息
public static function getUserGroup($userId): array
}
第 3 步:后台管理界面(1 天)
- 用户组管理:CRUD 用户组、设置默认组
- 版块权限设置:以版块为维度,勾选每个组的浏览/发帖/回复权限
- 用户管理:编辑用户时可选择所属用户组
第 4 步:前端权限拦截(0.5 天)
ForumController::category() → 检查 canView()ThreadController::show() → 检查 canView()PostController::create() → 检查 canPost()ThreadController::show() 的回复表单 → 检查 canReply()
第 5 步:现有等级系统的融合(已有,无需改动)
points 和 level 字段保持原样运行,与用户组互不干扰:
用户组 → 控制权限(能不能做某件事)
等级 → 展示 badge(做了事积累的荣誉)
五、后续可扩展
| 功能 | 扩展方式 |
|---|
| 发帖审核 | category_permissions 加 need_approve 字段 |
| 附件权限 | 加 can_upload_attachment 字段 |
| 可见版块列表 | 首页/版块列表按权限过滤显示 |
| 积分购买 VIP 组 | Points::award() 达标后自动切换 group_id |
六、工作量估计
| 步骤 | 内容 | 预估 |
|---|
| 1 | 建表 + Model | 0.5 天 |
| 2 | Permission Helper | 0.5 天 |
| 3 | 后台管理界面 | 1 天 |
| 4 | 前端权限拦截 | 0.5 天 |
| 5 | 数据迁移脚本 | 0.5 天 |
| 合计 | | 约 3 天 |
七、我的想法
- 等级和权限分开是对的——等级是"荣誉",用户组是"权限",两者互不依赖。现在的
points/level 系统可以原封不动保留。
- 权限检查点要精准——只需拦截三个关键入口:浏览版块列表、点击发帖按钮、提交回复表单。不需要在 Model 层做权限检查,Controller 层拦截就够了。
- 默认权限宽松——新增版块时默认所有组都有全部权限,管理员只需针对需要限制的版块去关闭某些组的权限,减少配置负担。
- 管理员不受限制——
group_id=4(管理员组)跳过所有权限检查,确保管理员不会把自己锁在外面。
要不要开始做?从第 1 步建表开始。