🛡️ 权限与菜单
SunAdmin 后台权限由“管理员 - 角色 - 菜单/权限标识”组成,前端动态路由也依赖后端菜单返回。
🎯 本页目标
读完本章节后,应能掌握:
- 后台与用户端的认证中间件分别要求什么模型、注入哪些属性。
- 何时使用普通
Get/Post、OpenGet/OpenPost、api.try-auth。 - 菜单数据如何与前端
src/views的.vue文件对应。 - 新增页面或按钮时应同步维护哪些菜单与权限数据。
🪛 核心目录
| 能力 | 后端路径 | 前端路径 |
|---|---|---|
| 动态路由 | MenuController@route | frontend/admin/src/router/index.ts |
| 当前用户信息 | AdminController@mySelf | frontend/admin/src/stores/modules/user.ts |
🔐 后台认证
后台接口默认挂载 admin.auth,中间件:
text
app/Core/Http/Middleware/AdminAuthMiddleware.php中间件要求 Sanctum 当前用户是:
php
Modules\System\Domain\Models\Auth\Admin认证通过后会写入:
php
$request->attributes->set('admin_id', $user->getKey());
$request->attributes->set('admin', $user);控制器内可使用:
php
$this->adminId();
$this->admin();👤 用户端认证
用户端 Api 目录默认挂载 api.site + api.auth,普通 Get/Post 接口默认需要用户登录。登录校验中间件:
text
app/Core/Http/Middleware/ApiAuthMiddleware.php认证通过后写入:
php
$request->attributes->set('user_id', $user->getKey());
$request->attributes->set('user', $user);控制器内可使用:
php
$this->userId();
$this->user();🪪 尝试登录
api.try-auth 适合在公开接口里做个性化逻辑。接口本身应使用 OpenGet / OpenPost 排除强制登录;游客可访问,携带有效 token 时可读取用户身份。
中间件类:
text
app/Core/Http/Middleware/ApiTryAuthMiddleware.php典型场景:
- 首页推荐。
- 文章列表。
- 上传临时文件。
- AI 推荐。
注意:涉及用户资料、地址、订单、账户资金等强身份数据时使用普通 Get/Post 即可,因为 Api 目录默认已经要求登录,不需要重复标注 api.auth。
🧭 菜单与动态路由
Admin 端动态路由来自后端菜单树。菜单中的 component 字段使用相对 src/views 的页面路径,前端启动时会扫描 src/views/**/*.vue 并按 component 加载对应组件。
在后台菜单管理页面可以直接选择 component,无需手工录入。

菜单类型:
| 类型 | 前端行为 |
|---|---|
| 目录 | 渲染为 Layout 或 RouterView |
| 菜单 | 加载真实页面组件 |
| 按钮/权限 | 不生成页面,用于操作权限判断 |
🏷️ 权限标识
权限标识通常放在菜单数据的 perms 字段。前端 user store 保存:
ts
perms: string[]用法示例:
vue
<el-button v-perm="['article.add']">新增</el-button>页面应通过权限标识控制按钮显示,例如新增、编辑、删除、审核、导出等。
➕ 新增权限流程
- 后端新增接口,并确定是默认登录接口还是
OpenGet/OpenPost公开接口。 - Admin 新增页面或按钮。
- 在菜单初始数据中新增菜单记录或按钮权限记录。
component写System/user/index这类相对src/views的路径。perms使用稳定、可读、可搜索的权限标识。- 登录后台后刷新权限,确认
refreshUserAccess()能拿到新菜单。
❓ 常见问题
| 问题 | 原因 | 处理 |
|---|---|---|
| 登录后 403 | 当前角色没有有效菜单 | 检查角色菜单授权 |
| 菜单点击组件缺失 | component 与前端路径不匹配 | 对照 src/views 修正 |
| 按钮不显示 | 权限标识未返回或页面判断错误 | 检查 perms |
| 新菜单本地有、部署没有 | 只改了数据库未改 Seeder | 同步初始数据 |
