600 lines
22 KiB
Markdown
600 lines
22 KiB
Markdown
# 盘古用户平台 - 系统设计文档
|
||
|
||
---
|
||
|
||
| 文档信息 | 内容 |
|
||
|---------|------|
|
||
| **文档版本** | V1.0 |
|
||
| **项目名称** | 盘古用户平台(Pangu User Platform) |
|
||
| **编写团队** | pangu |
|
||
| **创建日期** | 2026-01-31 |
|
||
|
||
---
|
||
|
||
## 1. 系统架构设计
|
||
|
||
### 1.1 整体架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ 客户端层 │
|
||
├─────────────────┬─────────────────┬─────────────────┬───────────────────┤
|
||
│ 管理后台 │ 小程序 │ H5 │ 第三方应用 │
|
||
│ (Vue 3) │ (微信小程序) │ (Vue/H5) │ (API调用) │
|
||
└────────┬────────┴────────┬────────┴────────┬────────┴────────┬──────────┘
|
||
│ │ │ │
|
||
▼ ▼ ▼ ▼
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ 网关层 (Nginx) │
|
||
│ - 负载均衡 - SSL终结 - 静态资源 │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ 应用服务层 (Spring Boot) │
|
||
├─────────────────────────────────────────────────────────────────────────┤
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
|
||
│ │ 认证模块 │ │ 用户模块 │ │ 学校模块 │ │ 应用模块 │ │
|
||
│ │ - JWT认证 │ │ - 会员管理 │ │ - 学校管理 │ │ - 应用管理 │ │
|
||
│ │ - 权限控制 │ │ - 学生管理 │ │ - 年级班级 │ │ - 接口授权 │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ └─────────────┘ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ 基础模块 │ │ 系统模块 │ │ 开放API │ │
|
||
│ │ - 区域管理 │ │ - 用户管理 │ │ - 对外接口 │ │
|
||
│ │ - 学科管理 │ │ - 角色权限 │ │ - 签名验证 │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
▼ ▼ ▼
|
||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||
│ MySQL │ │ Redis │ │ MinIO │
|
||
│ 主数据库 │ │ 缓存/会话 │ │ 文件存储 │
|
||
└─────────────┘ └─────────────┘ └─────────────┘
|
||
```
|
||
|
||
### 1.2 技术选型
|
||
|
||
| 层次 | 技术 | 版本 | 说明 |
|
||
|-----|------|------|------|
|
||
| **前端** | Vue | 3.x | 管理后台框架 |
|
||
| | Element Plus | 2.x | UI组件库 |
|
||
| | Axios | 1.x | HTTP客户端 |
|
||
| | Pinia | 2.x | 状态管理 |
|
||
| **后端** | Spring Boot | 3.3.x | 应用框架(LTS版本) |
|
||
| | Spring Security | 6.x | 安全框架 |
|
||
| | MyBatis Plus | 3.5.x | ORM框架 |
|
||
| | JWT | 0.12.x | Token认证 |
|
||
| | Hutool | 5.x | 工具库 |
|
||
| | JDK | 17+ | 运行环境(LTS) |
|
||
| **数据库** | MySQL | 8.0 | 主数据库 |
|
||
| | Redis | 7.x | 缓存 |
|
||
| **中间件** | Nginx | 1.20+ | 反向代理 |
|
||
| | MinIO | - | 文件存储(可选)|
|
||
| **基础框架** | RuoYi-Vue | 3.8.x | 快速开发框架 |
|
||
|
||
### 1.3 模块划分
|
||
|
||
```
|
||
pangu-user-platform/
|
||
├── pangu-admin/ # 后台管理模块
|
||
├── pangu-api/ # 移动端API模块
|
||
├── pangu-open/ # 开放平台API模块
|
||
├── pangu-common/ # 公共模块
|
||
│ ├── pangu-common-core/ # 核心工具
|
||
│ ├── pangu-common-redis/ # Redis工具
|
||
│ └── pangu-common-security/# 安全工具
|
||
├── pangu-framework/ # 框架核心
|
||
├── pangu-system/ # 系统模块(复用RuoYi)
|
||
├── pangu-generator/ # 代码生成器
|
||
└── pangu-ui/ # 前端工程
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 模块设计
|
||
|
||
### 2.1 认证模块
|
||
|
||
#### 2.1.1 后台用户认证
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 后台登录流程 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 用户 ──► 输入账号密码 ──► 输入验证码 ──► 登录请求 │
|
||
│ │ │
|
||
│ ▼ │
|
||
│ ┌─────────────────┐ │
|
||
│ │ 验证验证码 │ │
|
||
│ └────────┬────────┘ │
|
||
│ │ │
|
||
│ ┌────────▼────────┐ │
|
||
│ │ 验证账号密码 │ │
|
||
│ └────────┬────────┘ │
|
||
│ │ │
|
||
│ ┌────────▼────────┐ │
|
||
│ │ 检查账号状态 │ │
|
||
│ └────────┬────────┘ │
|
||
│ │ │
|
||
│ ┌────────▼────────┐ │
|
||
│ │ 生成JWT Token │ │
|
||
│ └────────┬────────┘ │
|
||
│ │ │
|
||
│ ┌────────▼────────┐ │
|
||
│ │ 缓存用户信息 │ │
|
||
│ └────────┬────────┘ │
|
||
│ ▼ │
|
||
│ 返回Token │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 2.1.2 会员端认证(三种方式)
|
||
|
||
**方式一:手机号 + 验证码登录**
|
||
|
||
```java
|
||
/**
|
||
* 验证码登录流程
|
||
* 1. 前端请求发送验证码
|
||
* 2. 后端生成6位验证码,存入Redis(5分钟有效)
|
||
* 3. 调用短信服务发送验证码
|
||
* 4. 前端提交手机号+验证码
|
||
* 5. 后端验证验证码,生成Token
|
||
*/
|
||
```
|
||
|
||
**方式二:手机号 + 密码登录**
|
||
|
||
```java
|
||
/**
|
||
* 密码登录流程
|
||
* 1. 前端提交手机号+密码
|
||
* 2. 后端查询会员信息
|
||
* 3. BCrypt验证密码
|
||
* 4. 检查账号状态
|
||
* 5. 生成Token返回
|
||
*/
|
||
```
|
||
|
||
**方式三:微信登录**
|
||
|
||
```java
|
||
/**
|
||
* 微信登录流程
|
||
* 1. 前端调用wx.login获取code
|
||
* 2. 前端提交code到后端
|
||
* 3. 后端调用微信接口换取openId
|
||
* 4. 根据openId查询会员
|
||
* 5. 已注册:直接生成Token
|
||
* 6. 未注册:创建新会员,生成Token
|
||
*/
|
||
```
|
||
|
||
#### 2.1.3 Token设计
|
||
|
||
| 字段 | 说明 |
|
||
|-----|------|
|
||
| sub | 用户ID |
|
||
| type | 用户类型(admin/member)|
|
||
| exp | 过期时间 |
|
||
| iat | 签发时间 |
|
||
|
||
**Token配置:**
|
||
- 后台用户Token有效期:30分钟(可续期)
|
||
- 会员Token有效期:7天
|
||
- Token存储位置:Redis
|
||
|
||
### 2.2 权限控制设计
|
||
|
||
#### 2.2.1 RBAC权限模型
|
||
|
||
```
|
||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||
│ 用户 │────▶│ 角色 │────▶│ 权限 │
|
||
└─────────┘ └─────────┘ └─────────┘
|
||
│ │ │
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||
│ 部门 │ │ 角色菜单 │ │ 菜单 │
|
||
└─────────┘ └─────────┘ └─────────┘
|
||
```
|
||
|
||
#### 2.2.2 数据权限控制
|
||
|
||
```java
|
||
/**
|
||
* 数据权限级别
|
||
* 1. 全部数据权限 - 超级管理员
|
||
* 2. 部门数据权限 - 分公司用户(只能看本区域数据)
|
||
* 3. 本人数据权限 - 学校用户(只能看本校数据)
|
||
*/
|
||
@DataScope(deptAlias = "d", userAlias = "u")
|
||
public List<School> selectSchoolList(School school) {
|
||
// 自动拼接数据权限SQL
|
||
}
|
||
```
|
||
|
||
### 2.3 学校模块设计
|
||
|
||
#### 2.3.1 数据结构
|
||
|
||
```
|
||
区域(Region)
|
||
└── 学校(School)
|
||
└── 年级关联(SchoolGrade)
|
||
└── 班级关联(SchoolClass)
|
||
```
|
||
|
||
#### 2.3.2 核心服务
|
||
|
||
```java
|
||
public interface ISchoolService {
|
||
|
||
/**
|
||
* 查询学校列表(树形结构)
|
||
*/
|
||
List<SchoolTreeVO> selectSchoolTree(Long regionId);
|
||
|
||
/**
|
||
* 新增学校
|
||
*/
|
||
int insertSchool(School school);
|
||
|
||
/**
|
||
* 编辑学校
|
||
*/
|
||
int updateSchool(School school);
|
||
|
||
/**
|
||
* 删除学校(检查关联)
|
||
*/
|
||
int deleteSchool(Long schoolId);
|
||
|
||
/**
|
||
* 为学校挂载年级
|
||
*/
|
||
int bindGrades(Long schoolId, List<Long> gradeIds);
|
||
|
||
/**
|
||
* 为年级挂载班级
|
||
*/
|
||
int bindClasses(Long schoolGradeId, List<Long> classIds);
|
||
}
|
||
```
|
||
|
||
### 2.4 会员模块设计
|
||
|
||
#### 2.4.1 会员与学生关系
|
||
|
||
```
|
||
┌─────────────┐ ┌─────────────┐
|
||
│ 会员 │ 1 n │ 学生 │
|
||
│ (Member) │◀─────────▶│ (Student) │
|
||
└─────────────┘ └─────────────┘
|
||
│
|
||
│ 身份类型
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 家长:可绑定任意学校的学生 │
|
||
│ 教师:只能绑定本校学生 │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 2.4.2 核心服务
|
||
|
||
```java
|
||
public interface IMemberService {
|
||
|
||
/**
|
||
* 会员登录(验证码)
|
||
*/
|
||
LoginVO loginBySms(String phone, String code);
|
||
|
||
/**
|
||
* 会员登录(密码)
|
||
*/
|
||
LoginVO loginByPassword(String phone, String password);
|
||
|
||
/**
|
||
* 会员登录(微信)
|
||
*/
|
||
LoginVO loginByWechat(String code);
|
||
|
||
/**
|
||
* 重置密码
|
||
*/
|
||
String resetPassword(Long memberId);
|
||
|
||
/**
|
||
* 绑定学生
|
||
*/
|
||
int bindStudent(Long memberId, Long studentId);
|
||
|
||
/**
|
||
* 解绑学生
|
||
*/
|
||
int unbindStudent(Long memberId, Long studentId);
|
||
}
|
||
```
|
||
|
||
### 2.5 应用模块设计
|
||
|
||
#### 2.5.1 应用认证流程
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────────────────┐
|
||
│ 第三方应用调用API流程 │
|
||
├────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 第三方应用 ──► 生成签名 ──► 发起请求 ──► 网关验证 ──► 业务处理 │
|
||
│ │
|
||
│ 签名规则: │
|
||
│ 1. 参数按ASCII排序 │
|
||
│ 2. 拼接成 key1=value1&key2=value2 格式 │
|
||
│ 3. 末尾追加 &appSecret=xxx │
|
||
│ 4. MD5加密得到sign │
|
||
│ │
|
||
│ 请求头: │
|
||
│ - X-App-Id: 应用编码 │
|
||
│ - X-Timestamp: 时间戳 │
|
||
│ - X-Sign: 签名 │
|
||
│ │
|
||
└────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 2.5.2 接口授权控制
|
||
|
||
```java
|
||
/**
|
||
* 接口授权拦截器
|
||
* 检查应用是否有权限访问当前接口
|
||
*/
|
||
@Component
|
||
public class ApiAuthInterceptor implements HandlerInterceptor {
|
||
|
||
@Override
|
||
public boolean preHandle(HttpServletRequest request,
|
||
HttpServletResponse response,
|
||
Object handler) {
|
||
String appId = request.getHeader("X-App-Id");
|
||
String uri = request.getRequestURI();
|
||
|
||
// 1. 验证签名
|
||
if (!verifySign(request)) {
|
||
throw new ApiException("签名验证失败");
|
||
}
|
||
|
||
// 2. 检查应用状态
|
||
Application app = applicationService.getByAppId(appId);
|
||
if (app == null || !app.isEnabled()) {
|
||
throw new ApiException("应用不存在或已禁用");
|
||
}
|
||
|
||
// 3. 检查接口授权
|
||
if (!app.hasPermission(uri)) {
|
||
throw new ApiException("无权访问该接口");
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 接口设计规范
|
||
|
||
### 3.1 RESTful API规范
|
||
|
||
| HTTP方法 | 用途 | 示例 |
|
||
|---------|------|------|
|
||
| GET | 查询资源 | GET /api/schools |
|
||
| POST | 创建资源 | POST /api/schools |
|
||
| PUT | 更新资源 | PUT /api/schools/{id} |
|
||
| DELETE | 删除资源 | DELETE /api/schools/{id} |
|
||
|
||
### 3.2 统一响应格式
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
// 业务数据
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 错误码定义
|
||
|
||
| 错误码 | 说明 |
|
||
|-------|------|
|
||
| 200 | 成功 |
|
||
| 400 | 请求参数错误 |
|
||
| 401 | 未授权 |
|
||
| 403 | 禁止访问 |
|
||
| 404 | 资源不存在 |
|
||
| 500 | 服务器错误 |
|
||
|
||
### 3.4 分页参数
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|-----|------|------|
|
||
| pageNum | int | 页码,从1开始 |
|
||
| pageSize | int | 每页条数,默认10 |
|
||
|
||
### 3.5 分页响应
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"total": 100,
|
||
"rows": [...]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 安全设计
|
||
|
||
### 4.1 密码安全
|
||
|
||
```java
|
||
/**
|
||
* 密码加密存储
|
||
* 使用BCrypt算法,自动加盐
|
||
*/
|
||
String encodedPassword = BCrypt.hashpw(rawPassword, BCrypt.gensalt());
|
||
|
||
/**
|
||
* 密码验证
|
||
*/
|
||
boolean matches = BCrypt.checkpw(rawPassword, encodedPassword);
|
||
```
|
||
|
||
### 4.2 防重放攻击
|
||
|
||
```java
|
||
/**
|
||
* 请求时间戳验证
|
||
* 请求时间与服务器时间相差不超过5分钟
|
||
*/
|
||
long timestamp = Long.parseLong(request.getHeader("X-Timestamp"));
|
||
if (Math.abs(System.currentTimeMillis() - timestamp) > 5 * 60 * 1000) {
|
||
throw new ApiException("请求已过期");
|
||
}
|
||
```
|
||
|
||
### 4.3 敏感数据脱敏
|
||
|
||
```java
|
||
/**
|
||
* 手机号脱敏:138****1234
|
||
*/
|
||
public static String maskPhone(String phone) {
|
||
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
|
||
}
|
||
```
|
||
|
||
### 4.4 SQL注入防护
|
||
|
||
- 使用MyBatis参数化查询
|
||
- 禁止拼接SQL语句
|
||
- 使用白名单校验排序字段
|
||
|
||
### 4.5 XSS防护
|
||
|
||
- 输入数据HTML转义
|
||
- 使用Content-Security-Policy头
|
||
- 设置HttpOnly Cookie
|
||
|
||
---
|
||
|
||
## 5. 缓存设计
|
||
|
||
### 5.1 缓存策略
|
||
|
||
| 缓存KEY | 过期时间 | 说明 |
|
||
|--------|---------|------|
|
||
| login_tokens:{token} | 30min/7day | 登录Token |
|
||
| captcha:{uuid} | 5min | 图形验证码 |
|
||
| sms_code:{phone} | 5min | 短信验证码 |
|
||
| user_info:{userId} | 30min | 用户信息 |
|
||
| dict_data:{dictType} | 永久 | 字典数据 |
|
||
| region_tree | 24h | 区域树 |
|
||
|
||
### 5.2 缓存更新策略
|
||
|
||
- 登录Token:登录时创建,退出时删除
|
||
- 用户信息:修改时删除,下次查询时重建
|
||
- 字典数据:修改时手动刷新
|
||
- 区域树:修改时手动刷新
|
||
|
||
---
|
||
|
||
## 6. 日志设计
|
||
|
||
### 6.1 日志级别
|
||
|
||
| 级别 | 使用场景 |
|
||
|-----|---------|
|
||
| ERROR | 系统异常、业务错误 |
|
||
| WARN | 警告信息、潜在问题 |
|
||
| INFO | 业务关键操作 |
|
||
| DEBUG | 调试信息(仅开发环境)|
|
||
|
||
### 6.2 操作日志
|
||
|
||
记录以下操作:
|
||
- 用户登录/登出
|
||
- 数据新增/修改/删除
|
||
- 密码重置
|
||
- 应用密钥重置
|
||
|
||
日志字段:
|
||
- 操作人
|
||
- 操作时间
|
||
- 操作模块
|
||
- 操作类型
|
||
- 操作描述
|
||
- 请求参数
|
||
- 响应结果
|
||
- IP地址
|
||
|
||
---
|
||
|
||
## 7. 部署架构
|
||
|
||
### 7.1 单机部署
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 服务器 (8C16G) │
|
||
├─────────────────────────────────────────┤
|
||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||
│ │ Nginx │ │ 后端 │ │ 前端 │ │
|
||
│ │ :80 │ │ :8080 │ │ 静态 │ │
|
||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||
│ │
|
||
│ ┌─────────┐ ┌─────────┐ │
|
||
│ │ MySQL │ │ Redis │ │
|
||
│ │ :3306 │ │ :6379 │ │
|
||
│ └─────────┘ └─────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 7.2 集群部署(预留)
|
||
|
||
```
|
||
┌─────────┐
|
||
│ SLB │
|
||
└────┬────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
▼ ▼ ▼
|
||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||
│ Nginx1 │ │ Nginx2 │ │ Nginx3 │
|
||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||
│ App1 │ │ App2 │ │ App3 │
|
||
└──────────┘ └──────────┘ └──────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
▼ ▼ ▼
|
||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||
│ MySQL主 │ │ MySQL从 │ │ Redis │
|
||
└──────────┘ └──────────┘ └──────────┘
|
||
```
|
||
|
||
---
|
||
|
||
*文档结束*
|