7.9 KiB
7.9 KiB
TokenController优化总结
🎯 优化目标
将TokenController从使用请求体传递token的方式改为标准的从请求头自动获取token的方式,符合RESTful API最佳实践。
✅ 完成的优化
1. 修改TokenController接口
优化前
@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类封装
- ❌ 客户端需要构造请求体
优化后
@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文档注解
@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 - 请求头: 无
- 请求体:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
优化后
- 请求方式:
GET /token/user-info - 请求头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - 请求体: 无
接口2: 获取用户名
优化前
- 请求方式:
POST /token/username - 请求头: 无
- 请求体:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
优化后
- 请求方式:
GET /token/username - 请求头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - 请求体: 无
接口3: 验证Token
优化前
- 请求方式:
POST /token/validate - 请求头: 无
- 请求体:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
优化后
- 请求方式:
GET /token/validate - 请求头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - 请求体: 无
🔧 Token提取机制
TokenUtil已经实现了标准的token提取逻辑:
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传递方式:
- 标准方式(推荐):
Authorization: Bearer {token} - 备用方式:URL参数
?token={token}
🚀 前端调用示例
优化前(不推荐)
// 需要在请求体中传递token
const response = await http.post('/token/user-info', {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
优化后(推荐)
// 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. 提高可维护性
- ✅ 代码结构更清晰
- ✅ 职责分离更明确
- ✅ 便于后续扩展
🔍 相关文件变更
修改的文件
backend-single/src/main/java/com/emotion/controller/TokenController.java- 修改所有接口从POST改为GET
- 参数从
@RequestBody TokenRequest改为HttpServletRequest - 添加Swagger API文档注解
- 添加详细的注释说明
删除的文件
backend-single/src/main/java/com/emotion/dto/request/TokenRequest.java- 不再需要此类
未修改的文件
TokenService.java- 接口已经是标准方式TokenServiceImpl.java- 实现已经是标准方式TokenUtil.java- 工具类已经支持标准方式
✅ 测试验证
测试用例
1. 测试获取用户信息
curl -X GET http://localhost:8080/token/user-info \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
预期结果:
{
"code": 200,
"message": "操作成功",
"data": {
"userId": "user_123",
"username": "testuser",
"email": "test@example.com"
}
}
2. 测试获取用户名
curl -X GET http://localhost:8080/token/username \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
预期结果:
{
"code": 200,
"message": "操作成功",
"data": "testuser"
}
3. 测试验证Token
curl -X GET http://localhost:8080/token/validate \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
预期结果:
{
"code": 200,
"message": "操作成功",
"data": "user_123"
}
4. 测试无效Token
curl -X GET http://localhost:8080/token/user-info \
-H "Authorization: Bearer invalid_token"
预期结果:
{
"code": 401,
"message": "访问令牌无效或已过期",
"data": null
}
5. 测试缺少Token
curl -X GET http://localhost:8080/token/user-info
预期结果:
{
"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标准和安全最佳实践:
- ✅ 标准化:使用标准的Authorization请求头传递token
- ✅ 简化:删除不必要的TokenRequest类
- ✅ 规范化:GET方法用于查询操作
- ✅ 文档化:添加完整的Swagger API文档
- ✅ 安全性:Token不在请求体中暴露
现在TokenController的实现更加专业、安全、易用!