权限控制规范
2026/10/26大约 2 分钟
权限控制规范
基座用 RBAC:用户-角色-菜单/权限点。接口鉴权由 app/middleware/AuthCheck.php + #[Permission] 注解完成,前端按钮用 v-auth 指令对齐同一权限点。
后端权限注解
系统接口在方法上声明权限点(use app\service\Permission;):
#[Get('/index')]
#[Permission(title: '用户列表', slug: 'system:user:index')]
public function index(Request $request): Response { /* ... */ }slug是权限唯一标识,title用于在权限管理里展示。AuthCheck校验 JWT 有效性并注入当前主体;#[Permission]再判定该主体角色是否含此 slug。- 公开/登录/回调接口可不挂
#[Permission],改由$noNeedLogin放行。
权限标识格式
统一 module:action:operation,分隔符只用冒号 :,禁止点号或混用:
- ✅
system:user:index、system:user:save、system:user:editPass、system:user:batchDelete - ❌
system.user.save、system:user.save
前端 v-auth 的值、后端 #[Permission] 的 slug、菜单里登记的权限点三者必须完全一致,否则按钮显隐与接口校验会错位。
前端权限指令
<ElButton v-auth="'system:user:save'">新建</ElButton>
<ArtButtonTable v-auth="'system:user:delete'" type="delete" @click="..." />v-auth 控制元素显隐;权威拦截仍在后端,前端只是体验层,不能当安全边界。
数据权限(行级)
除功能权限外,基座按行政级别与可见范围做行级过滤:
currentLevel():当前用户所有角色的最大 level(超管为PHP_INT_MAX)。currentDataScope():DataScopeService::resolve()解析出的{all, self, dept_ids}可见范围。BaseController::assertCanManage($level)/assertRowVisible():校验能否操作/查看目标行。
写涉及归属数据的接口时套用这两个断言,别只查功能权限就放行。
超级管理员
id === 1 为超级管理员,拥有全部权限、不受 #[Permission] 限制。is_admin(JWT payload 里)只是便捷标记(超管或 account_type 为管理员得出),能否操作具体功能仍以查库的 RBAC 结果为准,代码里不要仅凭 is_admin 放行。
缓存联动
改角色、菜单、权限分配后要清对应缓存,否则新权限不生效:UserInfoCache::clearUserAll() / clearByRole()、UserAuthCache、UserMenuCache。详见缓存规范。
