236 lines
7.6 KiB
Markdown
236 lines
7.6 KiB
Markdown
# Proto文件设计说明 - 3.1 认证Service层
|
||
|
||
## 一、设计依据
|
||
|
||
本proto设计基于以下技术文档:
|
||
- **微服务架构设计文档** - 确定服务职责和API设计
|
||
- **数据库设计文档** - 确定数据结构和字段定义
|
||
- **开发功能顺序文档** - 确定Service层接口需求
|
||
- **JWT设计** - 确定Token相关字段和验证流程
|
||
|
||
## 二、核心设计要点
|
||
|
||
### 2.1 单Token方案
|
||
- ✅ `LoginResponse` 和 `RegisterResponse` 只返回 `access_token`
|
||
- ✅ `RefreshTokenRequest` 使用 `access_token` 刷新(不是 `refresh_token`)
|
||
- ✅ Token存储在 `users.access_token` 字段中
|
||
- ✅ 单设备登录,新登录会覆盖旧Token
|
||
|
||
### 2.2 Token中包含star_id
|
||
- ✅ JWT Claims包含:`user_id`, `star_id`, `updated_at`
|
||
- ✅ 前端可以直接从Token解析获取 `star_id`
|
||
- ✅ 无需额外拼接或传递 `star_id`
|
||
|
||
### 2.3 粉丝身份隔离
|
||
- ✅ 所有业务操作都基于 `user_id + star_id`
|
||
- ✅ `FanProfile` 使用联合唯一索引 `(user_id, star_id)`
|
||
- ✅ 切换身份时生成新Token(包含新的 `star_id`)
|
||
|
||
### 2.4 数据库字段映射
|
||
|
||
#### User表字段映射
|
||
```protobuf
|
||
message User {
|
||
int64 id = 1; // users.id
|
||
string mobile = 2; // users.mobile
|
||
string avatar_url = 3; // users.avatar_url
|
||
string global_wallet_address = 4; // users.global_wallet_address
|
||
bool is_active = 5; // users.is_active
|
||
int64 created_at = 6; // users.created_at
|
||
}
|
||
```
|
||
|
||
**注意**:不包含敏感字段(`password_hash`, `access_token`, `token_expires_at`)
|
||
|
||
#### FanProfile表字段映射
|
||
```protobuf
|
||
message FanProfile {
|
||
int64 id = 1; // fan_profiles.id
|
||
int64 user_id = 2; // fan_profiles.user_id
|
||
int64 star_id = 3; // fan_profiles.star_id(核心隔离键)
|
||
string nickname = 4; // fan_profiles.nickname
|
||
int32 level = 5; // fan_profiles.level
|
||
int32 times = 6; // fan_profiles.times(剩余铸造次数)
|
||
int32 social = 7; // fan_profiles.social(好友个数)
|
||
int64 experience = 8; // fan_profiles.experience
|
||
int64 coin_balance = 9; // fan_profiles.coin_balance
|
||
int64 crystal_balance = 10; // fan_profiles.crystal_balance
|
||
repeated string tags = 11; // fan_profiles.tags(JSONB数组)
|
||
int64 created_at = 12; // fan_profiles.created_at
|
||
}
|
||
```
|
||
|
||
## 三、认证相关消息设计
|
||
|
||
### 3.1 RegisterRequest / RegisterResponse
|
||
|
||
**RegisterRequest**:
|
||
- `mobile` - 手机号(必填)
|
||
- `password` - 密码(必填)
|
||
- `star_id` - 选择第一个粉丝身份的明星ID(必填)
|
||
- `nickname` - 第一个粉丝身份的昵称(必填)
|
||
|
||
**RegisterResponse**:
|
||
- `base` - 基础响应(状态码、消息、时间戳)
|
||
- `access_token` - JWT Token(已包含 `star_id`)
|
||
- `expires_in` - Token过期时间(秒,7天=604800秒)
|
||
- `user` - 创建的用户信息
|
||
- `fan_profile` - 创建的粉丝档案
|
||
|
||
**业务逻辑**:
|
||
1. 创建用户(`users`表)
|
||
2. 创建第一个粉丝档案(`fan_profiles`表,事务)
|
||
3. 生成JWT Token(包含 `user_id`, `star_id`, `updated_at`)
|
||
4. 更新用户Token(`users.access_token`, `users.token_expires_at`)
|
||
|
||
### 3.2 LoginRequest / LoginResponse
|
||
|
||
**LoginRequest**:
|
||
- `mobile` - 手机号(必填)
|
||
- `password` - 密码(必填)
|
||
|
||
**LoginResponse**:
|
||
- `base` - 基础响应
|
||
- `access_token` - JWT Token(已包含 `star_id`)
|
||
- `expires_in` - Token过期时间(秒)
|
||
- `user` - 用户信息
|
||
- `fan_profile` - 当前粉丝档案(根据Token中的 `star_id`)
|
||
- `fan_profiles` - 用户的所有粉丝身份列表
|
||
|
||
**业务逻辑**:
|
||
1. 根据手机号查询用户
|
||
2. 验证密码(bcrypt比对)
|
||
3. 验证用户是否激活
|
||
4. 获取用户的粉丝档案列表
|
||
5. 生成JWT Token(包含当前 `star_id`,从第一个粉丝档案获取)
|
||
6. 更新用户Token
|
||
|
||
### 3.3 RefreshTokenRequest / RefreshTokenResponse
|
||
|
||
**RefreshTokenRequest**:
|
||
- `access_token` - 旧的access_token(单token方案)
|
||
|
||
**RefreshTokenResponse**:
|
||
- `base` - 基础响应
|
||
- `access_token` - 新的Access Token
|
||
- `expires_in` - Token过期时间(秒)
|
||
|
||
**业务逻辑**:
|
||
1. 解析旧Token(即使过期也要解析)
|
||
2. 查询用户
|
||
3. 验证旧Token是否匹配数据库中的Token
|
||
4. 验证 `updated_at` 是否匹配(如果用户信息更新,Token失效)
|
||
5. 生成新Token
|
||
6. 更新数据库中的Token
|
||
|
||
### 3.4 ValidateTokenRequest / ValidateTokenResponse
|
||
|
||
**ValidateTokenRequest**:
|
||
- `access_token` - 要验证的Token
|
||
|
||
**ValidateTokenResponse**:
|
||
- `base` - 基础响应
|
||
- `user_id` - Token关联的用户ID
|
||
- `star_id` - Token关联的明星ID
|
||
- `is_valid` - Token是否有效
|
||
- `expires_at` - Token过期时间戳(毫秒)
|
||
|
||
**业务逻辑**:
|
||
1. 解析Token
|
||
2. 验证签名和过期时间
|
||
3. 验证Token是否匹配数据库中的Token
|
||
4. 验证 `updated_at` 是否匹配
|
||
5. 返回验证结果
|
||
|
||
### 3.5 LogoutRequest / LogoutResponse
|
||
|
||
**LogoutRequest**:
|
||
- `access_token` - 要失效的Token(可选)
|
||
|
||
**LogoutResponse**:
|
||
- `base` - 基础响应
|
||
|
||
**业务逻辑**:
|
||
1. 从Token中提取 `user_id`
|
||
2. 清除用户Token(`users.access_token = NULL`, `users.token_expires_at = NULL`)
|
||
|
||
## 四、消息设计原则
|
||
|
||
### 4.1 字段编号规则
|
||
- 1-15:常用字段(占用1字节)
|
||
- 16-2047:一般字段
|
||
- 不要重用已删除字段的编号
|
||
- 新增字段只能追加,不能删除
|
||
|
||
### 4.2 数据类型选择
|
||
- **ID类型**:使用 `int64`(支持大整数)
|
||
- **时间戳**:使用 `int64`(Unix时间戳,毫秒)
|
||
- **布尔值**:使用 `bool`
|
||
- **数组**:使用 `repeated` 关键字
|
||
- **可选字段**:proto3中所有字段默认都是可选的
|
||
|
||
### 4.3 命名规范
|
||
- **消息类型**:PascalCase(如 `RegisterRequest`)
|
||
- **字段名**:snake_case(如 `access_token`)
|
||
- **RPC方法**:PascalCase(如 `Register`)
|
||
|
||
### 4.4 响应结构
|
||
- 所有Response的第一个字段必须是 `topfans.common.BaseResponse base = 1;`
|
||
- `BaseResponse` 包含状态码、错误消息、时间戳
|
||
|
||
## 五、REST API映射
|
||
|
||
使用 `google.api.annotations` 定义REST API路径:
|
||
|
||
```protobuf
|
||
rpc Login(LoginRequest) returns (LoginResponse) {
|
||
option (google.api.http) = {
|
||
post: "/api/v1/auth/login"
|
||
body: "*"
|
||
};
|
||
}
|
||
```
|
||
|
||
支持通过 grpc-gateway 自动生成REST API,无需手动实现HTTP路由。
|
||
|
||
## 六、与Service层接口的对应关系
|
||
|
||
### Service接口 → Proto消息
|
||
|
||
| Service方法 | Request | Response |
|
||
|------------|---------|----------|
|
||
| `Register(req)` | `RegisterRequest` | `RegisterResponse` |
|
||
| `Login(req)` | `LoginRequest` | `LoginResponse` |
|
||
| `Logout(req)` | `LogoutRequest` | `LogoutResponse` |
|
||
| `RefreshToken(req)` | `RefreshTokenRequest` | `RefreshTokenResponse` |
|
||
| `ValidateToken(req)` | `ValidateTokenRequest` | `ValidateTokenResponse` |
|
||
|
||
**注意**:Service层接口应使用proto定义的类型,而不是原生类型。
|
||
|
||
## 七、后续扩展
|
||
|
||
当前proto定义覆盖了3.1认证Service层的需求。后续可以添加:
|
||
- 用户信息Service相关消息(已在proto中定义)
|
||
- 粉丝身份Service相关消息(已在proto中定义)
|
||
- 社交功能相关消息(后续添加)
|
||
|
||
## 八、验证检查清单
|
||
|
||
- [x] 所有必需的消息类型已定义
|
||
- [x] 字段类型与数据库设计一致
|
||
- [x] 单Token方案已正确实现
|
||
- [x] Token中包含 `star_id` 的设计已体现
|
||
- [x] 粉丝身份隔离设计已体现
|
||
- [x] REST API路径已定义
|
||
- [x] RPC服务定义完整
|
||
- [x] 字段编号无冲突
|
||
- [x] 命名规范一致
|
||
|
||
## 九、下一步
|
||
|
||
1. 生成proto Go代码(运行 `make proto` 或手动执行protoc命令)
|
||
2. 验证生成的代码可以正常导入
|
||
3. 更新 `pkg/errors/errors.go` 使用proto类型
|
||
4. 开始开发Service层(使用proto类型)
|
||
|