TravelContentCreator/认证接口统一修复报告.md

194 lines
5.5 KiB
Markdown
Raw Normal View History

2025-07-28 16:52:18 +08:00
# 认证接口统一修复报告
## 问题分析
### 1. 认证方式不统一问题
系统中发现了三种不同的用户认证获取方式:
#### 方式一:`userService.getLoginUser(request)`
- **使用范围**大多数Controller
- **文件示例**
- `UserController.java`
- `MaterialController.java`
- `ProductController.java`
- `TopicController.java`
- `ContentController.java`
- 等等...
#### 方式二:`getCurrentUserId(request)`(自定义方法)
- **使用范围**`MaterialController.java`, `ContactController.java`, `MessageController.java`
- **实现方式**优先从request属性获取然后调用userService.getLoginUser()
#### 方式三:`UserContextHolder.get()`
- **使用范围**Service实现类
- **文件示例**
- `MaterialFolderServiceImpl.java`
- `MaterialServiceImpl.java`
- `ContentStyleServiceImpl.java`
- `TargetAudienceServiceImpl.java`
### 2. 前端报告的具体问题
根据前端反馈:
- `/materialfolder/tree` 接口返回 401 "用户未登录"
- `/materialfolder/list` 接口返回 400 Bad Request
- `/material/user/list` 接口工作正常
## 根本原因
1. **认证逻辑不一致**:不同接口使用不同的认证方式
2. **上下文获取失败**`UserContextHolder.get()` 在某些情况下返回null
3. **AOP权限检查与手动检查冲突**:既有@AuthCheck注解又有手动权限验证
## 已修复内容
### 1. MaterialFolderController统一认证方式
**修复前**
```java
// 使用UserContextHolder.get()可能返回null
User currentUser = UserContextHolder.get();
if (currentUser == null) {
return new BaseResponse<>(401, null, "用户未登录");
}
```
**修复后**
```java
// 统一使用getCurrentUserId方法
Long userId = getCurrentUserId(request);
```
**修复的接口**
- `getFolderTree()` - 获取文件夹树
- `getFolderById()` - 根据ID获取文件夹
- `getUserFolders()` - 获取用户文件夹列表
- `listFolderByPage()` - 分页获取文件夹列表
### 2. 添加权限检查
`listFolderByPage` 接口添加了:
- `@AuthCheck(mustRole = Constant.DEFAULT_ROLE)` 注解
- 用户ID设置确保只返回当前用户的文件夹
### 3. 编译错误修复
修复了海报生成相关的编译错误:
- `PosterGenerateServiceImpl.java`修正了PosterContent字段使用
- `PosterServiceImpl.java`修正了TypeReference使用改为ParameterizedTypeReference
- `PosterGenerateResponse.java`:统一了字段命名
## 统一配置修复
### 1. 移除重复配置
**修复前**
```yaml
# 两个不同的AIGC配置块
external-services:
poster-generate: ...
aigc:
server: ...
```
**修复后**
```yaml
# 统一到external-services配置
external-services:
poster-generate:
base-url: http://8.138.116.153:2714
# ...其他配置
```
## 推荐解决方案
### 1. 短期方案(已实施)
✅ 统一 MaterialFolderController 的认证方式
✅ 修复编译错误
✅ 统一配置文件
### 2. 长期方案(建议)
**2.1 认证方式标准化**
建议统一使用 `userService.getLoginUser(request)` 方式:
```java
// 推荐的标准写法
@GetMapping("/example")
@AuthCheck(mustRole = Constant.DEFAULT_ROLE)
public BaseResponse<Object> example(HttpServletRequest request) {
User currentUser = userService.getLoginUser(request);
Long userId = currentUser.getId();
// 业务逻辑...
}
```
**2.2 Service层重构**
Service实现类不应直接使用UserContextHolder而应该从Controller层接收userId参数
```java
// Service接口
public interface SomeService {
List<SomeVO> getUserData(Long userId);
}
// Controller调用
@GetMapping("/data")
@AuthCheck(mustRole = Constant.DEFAULT_ROLE)
public BaseResponse<List<SomeVO>> getData(HttpServletRequest request) {
User currentUser = userService.getLoginUser(request);
List<SomeVO> result = someService.getUserData(currentUser.getId());
return ResultUtils.success(result);
}
```
**2.3 移除冗余权限检查**
在已有@AuthCheck注解的方法中,移除手动权限验证:
```java
// 不推荐(冗余)
@AuthCheck(mustRole = Constant.ADMIN_ROLE)
public BaseResponse<Object> adminMethod(HttpServletRequest request) {
User user = userService.getLoginUser(request);
if (!Constant.ADMIN_ROLE.equals(user.getUserRole())) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "权限不足");
}
// ...
}
// 推荐(简洁)
@AuthCheck(mustRole = Constant.ADMIN_ROLE)
public BaseResponse<Object> adminMethod(HttpServletRequest request) {
// 直接进行业务逻辑,@AuthCheck已处理权限验证
// ...
}
```
## 测试验证
### 验证接口:
1.`/materialfolder/tree` - 文件夹树接口
2.`/materialfolder/list` - 文件夹列表接口
3.`/materialfolder/folders` - 用户文件夹接口
4.`/materialfolder/get/{id}` - 文件夹详情接口
### 预期结果:
- 认证成功的用户能正常访问自己的数据
- 返回正确的HTTP状态码和数据格式
- 权限控制正常工作
## 风险评估
### 低风险:
- ✅ MaterialFolderController修复已测试编译通过
- ✅ 配置统一(向后兼容)
### 中等风险:
- ⚠️ 其他Controller的认证方式统一需要逐个测试
- ⚠️ Service层重构影响范围较大
## 总结
当前已修复了MaterialFolderController的认证问题和编译错误这应该能解决前端报告的文件夹相关接口的401和400错误。建议在后续开发中逐步统一整个系统的认证方式以避免类似问题再次出现。