登录权限返回修改
This commit is contained in:
252
docs/login-menu-button-response/使用指南.md
Normal file
252
docs/login-menu-button-response/使用指南.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# 登录接口返回菜单树和按钮权限 - 使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
从本版本开始,登录接口(`POST /api/admin/login` 和 `POST /api/h5/login`)响应中新增了 `menus` 和 `buttons` 两个字段,用于直接返回结构化的菜单树和按钮权限列表,简化前端实现。
|
||||
|
||||
## 响应结构
|
||||
|
||||
### LoginResponse 字段说明
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"access_token": "xxx",
|
||||
"refresh_token": "xxx",
|
||||
"expires_in": 86400,
|
||||
"user": { ... },
|
||||
"permissions": ["user:menu", "user:create", "user:delete"],
|
||||
"menus": [
|
||||
{
|
||||
"id": 1,
|
||||
"perm_code": "user:menu",
|
||||
"name": "用户管理",
|
||||
"url": "/users",
|
||||
"sort": 1,
|
||||
"children": [
|
||||
{
|
||||
"id": 2,
|
||||
"perm_code": "user:list:menu",
|
||||
"name": "用户列表",
|
||||
"url": "/users/list",
|
||||
"sort": 10,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buttons": ["user:create", "user:delete", "user:update"]
|
||||
},
|
||||
"timestamp": 1638360000
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `permissions` | `[]string` | 所有权限码(向后兼容,包含菜单和按钮) |
|
||||
| `menus` | `[]MenuNode` | 菜单树(树形结构) |
|
||||
| `buttons` | `[]string` | 按钮权限码列表(扁平数组) |
|
||||
|
||||
### MenuNode 结构说明
|
||||
|
||||
```typescript
|
||||
interface MenuNode {
|
||||
id: number; // 权限 ID
|
||||
perm_code: string; // 权限码(如 "user:menu")
|
||||
name: string; // 菜单名称(如 "用户管理")
|
||||
url: string; // 路由路径(如 "/users")
|
||||
sort: number; // 排序值(升序)
|
||||
children: MenuNode[]; // 子菜单(递归结构)
|
||||
}
|
||||
```
|
||||
|
||||
## 前端使用示例
|
||||
|
||||
### 1. 登录并缓存菜单数据
|
||||
|
||||
```javascript
|
||||
// 登录
|
||||
const response = await api.post('/api/admin/login', {
|
||||
username: 'admin',
|
||||
password: 'password',
|
||||
device: 'web'
|
||||
});
|
||||
|
||||
const { menus, buttons, permissions } = response.data;
|
||||
|
||||
// 缓存到 localStorage(推荐)
|
||||
localStorage.setItem('menus', JSON.stringify(menus));
|
||||
localStorage.setItem('buttons', JSON.stringify(buttons));
|
||||
localStorage.setItem('permissions', JSON.stringify(permissions));
|
||||
```
|
||||
|
||||
### 2. 渲染侧边栏菜单
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<aside class="sidebar">
|
||||
<menu-tree :items="menus" />
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
menus: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 从 localStorage 读取
|
||||
const cached = localStorage.getItem('menus');
|
||||
this.menus = cached ? JSON.parse(cached) : [];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 控制按钮显示
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<button v-if="hasPermission('user:create')">创建用户</button>
|
||||
<button v-if="hasPermission('user:delete')">删除用户</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
buttons: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 从 localStorage 读取
|
||||
const cached = localStorage.getItem('buttons');
|
||||
this.buttons = cached ? JSON.parse(cached) : [];
|
||||
},
|
||||
methods: {
|
||||
hasPermission(code) {
|
||||
return this.buttons.includes(code);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
### 4. 页面刷新时恢复菜单
|
||||
|
||||
```javascript
|
||||
// App.vue 或 main.js
|
||||
const menus = localStorage.getItem('menus');
|
||||
if (menus) {
|
||||
store.commit('setMenus', JSON.parse(menus));
|
||||
} else {
|
||||
// 未登录,跳转到登录页
|
||||
router.push('/login');
|
||||
}
|
||||
```
|
||||
|
||||
## 核心特性
|
||||
|
||||
### 1. 平台过滤
|
||||
|
||||
登录时传递 `device` 参数(`web` 或 `h5`),系统会自动过滤对应平台的权限:
|
||||
|
||||
```javascript
|
||||
// Web 后台登录
|
||||
await api.post('/api/admin/login', {
|
||||
username: 'admin',
|
||||
password: 'password',
|
||||
device: 'web' // 只返回 platform="web" 或 "all" 的菜单
|
||||
});
|
||||
|
||||
// H5 端登录
|
||||
await api.post('/api/h5/login', {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
device: 'h5' // 只返回 platform="h5" 或 "all" 的菜单
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 菜单自动排序
|
||||
|
||||
菜单树已按 `sort` 字段升序排序(包含所有层级),前端无需再次排序,直接渲染即可。
|
||||
|
||||
### 3. 超级管理员
|
||||
|
||||
超级管理员(`user_type = 1`)登录时,返回所有启用的菜单和按钮(仍然应用平台过滤)。
|
||||
|
||||
### 4. 孤儿节点处理
|
||||
|
||||
如果用户有子菜单权限但没有父菜单权限(如只有 "用户列表" 权限但没有 "用户管理" 权限),子菜单会被提升为根节点显示,避免菜单丢失。
|
||||
|
||||
## GetMe 接口行为
|
||||
|
||||
`GET /api/admin/me` 和 `GET /api/h5/me` 接口**不返回** `menus` 和 `buttons` 字段,只返回 `user` 和 `permissions`。
|
||||
|
||||
原因:
|
||||
- GetMe 是高频接口(如每次路由切换都调用)
|
||||
- 菜单树构建有计算成本
|
||||
- 前端应将菜单数据缓存到 localStorage
|
||||
|
||||
```json
|
||||
// GetMe 响应示例
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"user": { ... },
|
||||
"permissions": ["user:menu", "user:create"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 向后兼容性
|
||||
|
||||
- 旧版前端仍可使用 `permissions` 字段正常工作
|
||||
- 新版前端可以选择使用 `menus` 和 `buttons` 字段
|
||||
- `permissions` 字段包含所有权限码(菜单 + 按钮)
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **登录后立即缓存**:将 `menus` 和 `buttons` 存储到 localStorage,避免重复构建
|
||||
2. **页面刷新时恢复**:从 localStorage 读取菜单数据,无需重新登录
|
||||
3. **权限变更后刷新**:管理员修改权限后,提示用户重新登录或提供"刷新权限"按钮
|
||||
4. **使用 buttons 控制按钮**:不要使用 `permissions` 字段判断按钮显示,使用 `buttons` 更清晰
|
||||
5. **GetMe 不依赖菜单**:GetMe 接口用于验证 Token 有效性和获取用户信息,不要期望它返回菜单
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 权限变更后菜单未更新?
|
||||
|
||||
**原因**:前端使用了缓存的菜单数据。
|
||||
|
||||
**解决方案**:
|
||||
- 短期:提示用户重新登录
|
||||
- 长期:提供"刷新权限"按钮,调用 `POST /api/admin/login` 重新获取菜单
|
||||
|
||||
### 2. 菜单层级不正确?
|
||||
|
||||
**原因**:权限配置不当(子菜单的 `parent_id` 指向不存在的父菜单)。
|
||||
|
||||
**解决方案**:检查权限配置,确保父子关系正确。孤儿节点会被提升为根节点,同时后端会记录警告日志。
|
||||
|
||||
### 3. 性能影响?
|
||||
|
||||
**影响**:登录响应时间增加 < 50ms(权限数量 < 100 的场景)
|
||||
|
||||
**缓解**:
|
||||
- 前端缓存菜单数据到 localStorage
|
||||
- GetMe 接口未修改,性能无影响
|
||||
|
||||
### 4. 响应体过大?
|
||||
|
||||
**影响**:响应体增加约 5-10KB(取决于权限数量)
|
||||
|
||||
**缓解**:
|
||||
- 使用 Gzip 压缩(压缩率约 60-70%)
|
||||
- 前端缓存,登录后只传输一次
|
||||
Reference in New Issue
Block a user