294 lines
7.0 KiB
Markdown
294 lines
7.0 KiB
Markdown
|
|
# 后端限流配置修复说明
|
|||
|
|
|
|||
|
|
## 🐛 问题描述
|
|||
|
|
|
|||
|
|
**现象**: 第一次点击登录就提示"登录过于频繁,请1秒后再试"
|
|||
|
|
|
|||
|
|
**错误信息**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"message": "登录过于频繁,请1秒后再试",
|
|||
|
|
"data": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔍 问题原因
|
|||
|
|
|
|||
|
|
### 原始配置
|
|||
|
|
在 `AuthController.java` 第42行:
|
|||
|
|
```java
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 1, message = "登录过于频繁,请1秒后再试")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 问题分析
|
|||
|
|
1. **限流太严格**: `permitsPerSecond = 1` 表示每秒只允许1次请求
|
|||
|
|
2. **Guava RateLimiter 特性**: 使用令牌桶算法,第一次请求会立即消耗令牌
|
|||
|
|
3. **IP 限流**: 基于 IP 地址限流,本地开发时所有请求都是同一个 IP
|
|||
|
|
4. **缓存问题**: `RateLimiter` 实例被缓存,重启前的限流状态会保留
|
|||
|
|
|
|||
|
|
## ✅ 解决方案
|
|||
|
|
|
|||
|
|
### 1. 调整限流配置
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```java
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 1, message = "登录过于频繁,请1秒后再试")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```java
|
|||
|
|
// 调整限流:每秒5次请求,避免正常使用时触发限流
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 5, message = "登录过于频繁,请稍后再试")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 配置说明
|
|||
|
|
|
|||
|
|
| 参数 | 原值 | 新值 | 说明 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| permitsPerSecond | 1 | 5 | 每秒允许的请求数 |
|
|||
|
|
| message | 登录过于频繁,请1秒后再试 | 登录过于频繁,请稍后再试 | 错误提示 |
|
|||
|
|
|
|||
|
|
### 3. 为什么选择 5 次/秒
|
|||
|
|
|
|||
|
|
- ✅ **正常使用**: 用户正常点击不会超过5次/秒
|
|||
|
|
- ✅ **防止暴力破解**: 仍然能有效防止暴力破解攻击
|
|||
|
|
- ✅ **开发测试**: 方便开发和测试
|
|||
|
|
- ✅ **用户体验**: 不会影响正常用户体验
|
|||
|
|
|
|||
|
|
## 📝 修改的文件
|
|||
|
|
|
|||
|
|
### `backend/src/main/java/com/peidu/controller/AuthController.java`
|
|||
|
|
|
|||
|
|
**位置**: 第42行
|
|||
|
|
|
|||
|
|
**修改内容**:
|
|||
|
|
```java
|
|||
|
|
// 第42行
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 5, message = "登录过于频繁,请稍后再试")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔄 如何应用修改
|
|||
|
|
|
|||
|
|
### 方法1: 重新编译运行(推荐)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 进入后端目录
|
|||
|
|
cd backend
|
|||
|
|
|
|||
|
|
# 2. 清理并编译
|
|||
|
|
mvn clean package -DskipTests
|
|||
|
|
|
|||
|
|
# 3. 重启后端服务
|
|||
|
|
java -jar target/peidu-backend.jar
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方法2: IDEA 热部署
|
|||
|
|
|
|||
|
|
1. 在 IDEA 中修改代码
|
|||
|
|
2. 点击 "Build" → "Rebuild Project"
|
|||
|
|
3. 等待自动重启
|
|||
|
|
|
|||
|
|
### 方法3: 清除限流缓存
|
|||
|
|
|
|||
|
|
如果不想重启,可以添加一个清除缓存的接口:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@GetMapping("/clear-rate-limit")
|
|||
|
|
public Result<Void> clearRateLimit() {
|
|||
|
|
rateLimitConfig.cleanExpiredRateLimiters();
|
|||
|
|
return Result.success();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🧪 测试验证
|
|||
|
|
|
|||
|
|
### 1. 重启后端服务
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 停止当前服务
|
|||
|
|
# Ctrl + C 或 kill 进程
|
|||
|
|
|
|||
|
|
# 重新启动
|
|||
|
|
java -jar target/peidu-backend.jar
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 测试登录接口
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用 curl 测试
|
|||
|
|
curl -X POST http://localhost:8089/api/auth/login \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{
|
|||
|
|
"phone": "13800138000",
|
|||
|
|
"password": "123456"
|
|||
|
|
}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 预期结果
|
|||
|
|
|
|||
|
|
**成功响应**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "登录成功",
|
|||
|
|
"data": {
|
|||
|
|
"token": "eyJhbGc...",
|
|||
|
|
"userInfo": {...}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**限流响应**(快速连续请求6次以上):
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"message": "登录过于频繁,请稍后再试",
|
|||
|
|
"data": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 其他接口的限流配置
|
|||
|
|
|
|||
|
|
### 当前配置一览
|
|||
|
|
|
|||
|
|
| 接口 | 限流类型 | 速率 | 说明 |
|
|||
|
|
|------|----------|------|------|
|
|||
|
|
| `/api/auth/login` | IP | 5次/秒 | ✅ 已修改 |
|
|||
|
|
| `/api/auth/register` | IP | 已禁用 | 方便测试 |
|
|||
|
|
| `/api/auth/send-code` | IP | 1次/分钟 | 合理 |
|
|||
|
|
| `/api/auth/wx-login` | 无 | 无限制 | 建议添加 |
|
|||
|
|
|
|||
|
|
### 建议添加微信登录限流
|
|||
|
|
|
|||
|
|
在 `AuthController.java` 的微信登录接口添加:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@ApiOperation("微信登录")
|
|||
|
|
@PostMapping("/wx-login")
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 5, message = "登录过于频繁,请稍后再试")
|
|||
|
|
public Result<Map<String, Object>> wxLogin(@RequestBody WxLoginRequest request) {
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎯 生产环境建议
|
|||
|
|
|
|||
|
|
### 推荐配置
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 登录接口:每秒3次
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 3, message = "登录过于频繁,请稍后再试")
|
|||
|
|
|
|||
|
|
// 注册接口:每秒1次
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 1, message = "注册过于频繁,请稍后再试")
|
|||
|
|
|
|||
|
|
// 发送验证码:每分钟1次
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 0.0167, message = "验证码发送过于频繁,请1分钟后再试")
|
|||
|
|
|
|||
|
|
// 微信登录:每秒3次
|
|||
|
|
@RateLimit(limitType = RateLimit.LimitType.IP, permitsPerSecond = 3, message = "登录过于频繁,请稍后再试")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 配置原则
|
|||
|
|
|
|||
|
|
1. **登录类接口**: 3-5次/秒,平衡安全和体验
|
|||
|
|
2. **注册类接口**: 1次/秒,防止批量注册
|
|||
|
|
3. **验证码接口**: 1次/分钟,防止短信轰炸
|
|||
|
|
4. **业务接口**: 根据实际情况调整
|
|||
|
|
|
|||
|
|
## ⚠️ 注意事项
|
|||
|
|
|
|||
|
|
### 1. 开发环境 vs 生产环境
|
|||
|
|
|
|||
|
|
**开发环境**:
|
|||
|
|
- 可以适当放宽限流
|
|||
|
|
- 方便测试和调试
|
|||
|
|
- 建议 5-10次/秒
|
|||
|
|
|
|||
|
|
**生产环境**:
|
|||
|
|
- 需要严格限流
|
|||
|
|
- 防止恶意攻击
|
|||
|
|
- 建议 1-3次/秒
|
|||
|
|
|
|||
|
|
### 2. 限流类型选择
|
|||
|
|
|
|||
|
|
**IP 限流** (`RateLimit.LimitType.IP`):
|
|||
|
|
- 优点:简单有效
|
|||
|
|
- 缺点:同一 IP 下的所有用户共享限额
|
|||
|
|
- 适用:登录、注册等公开接口
|
|||
|
|
|
|||
|
|
**用户限流** (`RateLimit.LimitType.USER`):
|
|||
|
|
- 优点:精确控制每个用户
|
|||
|
|
- 缺点:需要用户已登录
|
|||
|
|
- 适用:业务接口、敏感操作
|
|||
|
|
|
|||
|
|
### 3. 缓存清理
|
|||
|
|
|
|||
|
|
`RateLimiter` 实例会被缓存,建议:
|
|||
|
|
- 定期清理过期的限流器
|
|||
|
|
- 重启服务会清空所有缓存
|
|||
|
|
- 可以添加管理接口手动清理
|
|||
|
|
|
|||
|
|
## 🔧 故障排查
|
|||
|
|
|
|||
|
|
### 问题1: 修改后仍然限流
|
|||
|
|
|
|||
|
|
**原因**: 缓存未清除
|
|||
|
|
**解决**: 重启后端服务
|
|||
|
|
|
|||
|
|
### 问题2: 所有用户都被限流
|
|||
|
|
|
|||
|
|
**原因**: 使用了 IP 限流,本地开发都是同一 IP
|
|||
|
|
**解决**:
|
|||
|
|
- 开发环境放宽限流
|
|||
|
|
- 或改用用户限流
|
|||
|
|
|
|||
|
|
### 问题3: 限流配置不生效
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
- 注解位置错误
|
|||
|
|
- AOP 未生效
|
|||
|
|
- 依赖未引入
|
|||
|
|
|
|||
|
|
**解决**:
|
|||
|
|
- 检查注解是否在正确的方法上
|
|||
|
|
- 检查 `@Aspect` 是否生效
|
|||
|
|
- 检查 Guava 依赖
|
|||
|
|
|
|||
|
|
## 📚 相关代码
|
|||
|
|
|
|||
|
|
### RateLimitAspect.java
|
|||
|
|
限流切面实现,拦截带有 `@RateLimit` 注解的方法
|
|||
|
|
|
|||
|
|
### RateLimitConfig.java
|
|||
|
|
限流配置类,管理 `RateLimiter` 实例缓存
|
|||
|
|
|
|||
|
|
### RateLimit.java
|
|||
|
|
限流注解定义
|
|||
|
|
|
|||
|
|
## ✅ 修改完成清单
|
|||
|
|
|
|||
|
|
- [x] 修改登录接口限流配置
|
|||
|
|
- [x] 调整 permitsPerSecond 从 1 到 5
|
|||
|
|
- [x] 优化错误提示信息
|
|||
|
|
- [ ] 重启后端服务(需要手动执行)
|
|||
|
|
- [ ] 测试验证(需要手动执行)
|
|||
|
|
- [ ] 考虑添加微信登录限流(可选)
|
|||
|
|
|
|||
|
|
## 🎉 总结
|
|||
|
|
|
|||
|
|
修改后的配置:
|
|||
|
|
- ✅ 不会在第一次请求时就触发限流
|
|||
|
|
- ✅ 仍然能有效防止暴力破解
|
|||
|
|
- ✅ 提供更好的用户体验
|
|||
|
|
- ✅ 方便开发和测试
|
|||
|
|
|
|||
|
|
**下一步**: 重启后端服务,然后重新测试登录功能!
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**修改时间**: 2026-02-03
|
|||
|
|
**修改文件**: `backend/src/main/java/com/peidu/controller/AuthController.java`
|
|||
|
|
**状态**: ✅ 已修改,待重启服务
|