338 lines
7.9 KiB
Markdown
338 lines
7.9 KiB
Markdown
# TokenController优化总结
|
||
|
||
## 🎯 优化目标
|
||
|
||
将TokenController从使用请求体传递token的方式改为标准的从请求头自动获取token的方式,符合RESTful API最佳实践。
|
||
|
||
## ✅ 完成的优化
|
||
|
||
### 1. 修改TokenController接口
|
||
|
||
#### 优化前
|
||
```java
|
||
@PostMapping("/user-info")
|
||
public Result<UserInfoResponse> getUserInfoByToken(@RequestBody @Validated TokenRequest request) {
|
||
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request.getToken());
|
||
return Result.success(userInfo);
|
||
}
|
||
```
|
||
|
||
**问题**:
|
||
- ❌ 使用POST方法获取数据(不符合RESTful规范)
|
||
- ❌ Token在请求体中传递(不安全,不标准)
|
||
- ❌ 需要额外的TokenRequest类封装
|
||
- ❌ 客户端需要构造请求体
|
||
|
||
#### 优化后
|
||
```java
|
||
@GetMapping("/user-info")
|
||
@Operation(summary = "获取用户信息", description = "通过请求头中的token获取当前用户信息")
|
||
public Result<UserInfoResponse> getUserInfoByToken(HttpServletRequest request) {
|
||
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request);
|
||
return Result.success(userInfo);
|
||
}
|
||
```
|
||
|
||
**改进**:
|
||
- ✅ 使用GET方法获取数据(符合RESTful规范)
|
||
- ✅ Token从请求头Authorization自动提取
|
||
- ✅ 不需要额外的Request类
|
||
- ✅ 客户端只需设置请求头
|
||
|
||
### 2. 删除TokenRequest类
|
||
|
||
**删除的文件**:
|
||
- `backend-single/src/main/java/com/emotion/dto/request/TokenRequest.java`
|
||
|
||
**原因**:
|
||
- 不再需要通过请求体传递token
|
||
- 简化代码结构
|
||
- 减少不必要的类
|
||
|
||
### 3. 添加API文档注解
|
||
|
||
```java
|
||
@Tag(name = "Token管理", description = "Token验证和用户信息获取")
|
||
public class TokenController {
|
||
|
||
@GetMapping("/user-info")
|
||
@Operation(summary = "获取用户信息", description = "通过请求头中的token获取当前用户信息")
|
||
public Result<UserInfoResponse> getUserInfoByToken(HttpServletRequest request) {
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📊 接口变更对比
|
||
|
||
### 接口1: 获取用户信息
|
||
|
||
#### 优化前
|
||
- **请求方式**: `POST /token/user-info`
|
||
- **请求头**: 无
|
||
- **请求体**:
|
||
```json
|
||
{
|
||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
}
|
||
```
|
||
|
||
#### 优化后
|
||
- **请求方式**: `GET /token/user-info`
|
||
- **请求头**:
|
||
```
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
- **请求体**: 无
|
||
|
||
---
|
||
|
||
### 接口2: 获取用户名
|
||
|
||
#### 优化前
|
||
- **请求方式**: `POST /token/username`
|
||
- **请求头**: 无
|
||
- **请求体**:
|
||
```json
|
||
{
|
||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
}
|
||
```
|
||
|
||
#### 优化后
|
||
- **请求方式**: `GET /token/username`
|
||
- **请求头**:
|
||
```
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
- **请求体**: 无
|
||
|
||
---
|
||
|
||
### 接口3: 验证Token
|
||
|
||
#### 优化前
|
||
- **请求方式**: `POST /token/validate`
|
||
- **请求头**: 无
|
||
- **请求体**:
|
||
```json
|
||
{
|
||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
}
|
||
```
|
||
|
||
#### 优化后
|
||
- **请求方式**: `GET /token/validate`
|
||
- **请求头**:
|
||
```
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
- **请求体**: 无
|
||
|
||
## 🔧 Token提取机制
|
||
|
||
TokenUtil已经实现了标准的token提取逻辑:
|
||
|
||
```java
|
||
public String extractToken(HttpServletRequest request) {
|
||
// 1. 优先从Authorization请求头获取(标准方式)
|
||
String authHeader = request.getHeader("Authorization");
|
||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||
return authHeader.substring(7);
|
||
}
|
||
|
||
// 2. 备用方案:从请求参数获取
|
||
String tokenParam = request.getParameter("token");
|
||
if (tokenParam != null && !tokenParam.trim().isEmpty()) {
|
||
return tokenParam.trim();
|
||
}
|
||
|
||
return null;
|
||
}
|
||
```
|
||
|
||
**支持的Token传递方式**:
|
||
1. **标准方式**(推荐):`Authorization: Bearer {token}`
|
||
2. **备用方式**:URL参数 `?token={token}`
|
||
|
||
## 🚀 前端调用示例
|
||
|
||
### 优化前(不推荐)
|
||
```typescript
|
||
// 需要在请求体中传递token
|
||
const response = await http.post('/token/user-info', {
|
||
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
||
})
|
||
```
|
||
|
||
### 优化后(推荐)
|
||
```typescript
|
||
// Token自动从localStorage获取并添加到请求头
|
||
const response = await http.get('/token/user-info')
|
||
|
||
// 或者手动设置(如果需要)
|
||
const response = await http.get('/token/user-info', {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
})
|
||
```
|
||
|
||
## 📝 优化收益
|
||
|
||
### 1. 符合标准规范
|
||
- ✅ 遵循RESTful API设计原则
|
||
- ✅ 使用标准的Authorization请求头
|
||
- ✅ GET方法用于查询,POST方法用于修改
|
||
|
||
### 2. 提升安全性
|
||
- ✅ Token不在请求体中暴露
|
||
- ✅ 减少token在日志中被记录的风险
|
||
- ✅ 符合OAuth 2.0和JWT标准
|
||
|
||
### 3. 简化代码
|
||
- ✅ 删除不必要的TokenRequest类
|
||
- ✅ 减少代码维护成本
|
||
- ✅ 统一token处理方式
|
||
|
||
### 4. 改善开发体验
|
||
- ✅ 前端不需要构造请求体
|
||
- ✅ 自动从请求头提取token
|
||
- ✅ 更清晰的API文档
|
||
|
||
### 5. 提高可维护性
|
||
- ✅ 代码结构更清晰
|
||
- ✅ 职责分离更明确
|
||
- ✅ 便于后续扩展
|
||
|
||
## 🔍 相关文件变更
|
||
|
||
### 修改的文件
|
||
1. `backend-single/src/main/java/com/emotion/controller/TokenController.java`
|
||
- 修改所有接口从POST改为GET
|
||
- 参数从`@RequestBody TokenRequest`改为`HttpServletRequest`
|
||
- 添加Swagger API文档注解
|
||
- 添加详细的注释说明
|
||
|
||
### 删除的文件
|
||
1. `backend-single/src/main/java/com/emotion/dto/request/TokenRequest.java`
|
||
- 不再需要此类
|
||
|
||
### 未修改的文件
|
||
1. `TokenService.java` - 接口已经是标准方式
|
||
2. `TokenServiceImpl.java` - 实现已经是标准方式
|
||
3. `TokenUtil.java` - 工具类已经支持标准方式
|
||
|
||
## ✅ 测试验证
|
||
|
||
### 测试用例
|
||
|
||
#### 1. 测试获取用户信息
|
||
```bash
|
||
curl -X GET http://localhost:8080/token/user-info \
|
||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
```
|
||
|
||
**预期结果**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "操作成功",
|
||
"data": {
|
||
"userId": "user_123",
|
||
"username": "testuser",
|
||
"email": "test@example.com"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 测试获取用户名
|
||
```bash
|
||
curl -X GET http://localhost:8080/token/username \
|
||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
```
|
||
|
||
**预期结果**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "操作成功",
|
||
"data": "testuser"
|
||
}
|
||
```
|
||
|
||
#### 3. 测试验证Token
|
||
```bash
|
||
curl -X GET http://localhost:8080/token/validate \
|
||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
```
|
||
|
||
**预期结果**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "操作成功",
|
||
"data": "user_123"
|
||
}
|
||
```
|
||
|
||
#### 4. 测试无效Token
|
||
```bash
|
||
curl -X GET http://localhost:8080/token/user-info \
|
||
-H "Authorization: Bearer invalid_token"
|
||
```
|
||
|
||
**预期结果**:
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"message": "访问令牌无效或已过期",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 5. 测试缺少Token
|
||
```bash
|
||
curl -X GET http://localhost:8080/token/user-info
|
||
```
|
||
|
||
**预期结果**:
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"message": "未提供访问令牌",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
## 📚 最佳实践
|
||
|
||
### 1. Token传递方式
|
||
- ✅ **推荐**:使用`Authorization: Bearer {token}`请求头
|
||
- ⚠️ **备用**:使用URL参数`?token={token}`(仅在特殊场景)
|
||
- ❌ **不推荐**:在请求体中传递token
|
||
|
||
### 2. HTTP方法选择
|
||
- ✅ **GET**:获取资源(如获取用户信息、验证token)
|
||
- ✅ **POST**:创建资源(如登录、注册)
|
||
- ✅ **PUT/PATCH**:更新资源
|
||
- ✅ **DELETE**:删除资源
|
||
|
||
### 3. 安全建议
|
||
- 使用HTTPS传输token
|
||
- 设置合理的token过期时间
|
||
- 实现token刷新机制
|
||
- 记录token使用日志
|
||
|
||
## 🎯 总结
|
||
|
||
通过这次优化,TokenController已经完全符合RESTful API标准和安全最佳实践:
|
||
|
||
1. ✅ **标准化**:使用标准的Authorization请求头传递token
|
||
2. ✅ **简化**:删除不必要的TokenRequest类
|
||
3. ✅ **规范化**:GET方法用于查询操作
|
||
4. ✅ **文档化**:添加完整的Swagger API文档
|
||
5. ✅ **安全性**:Token不在请求体中暴露
|
||
|
||
现在TokenController的实现更加专业、安全、易用!
|