| package middleware |
|
|
| import ( |
| "context" |
| "fmt" |
| "net/http" |
| "time" |
|
|
| "github.com/QuantumNous/new-api/common" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| const ( |
| EmailVerificationRateLimitMark = "EV" |
| EmailVerificationMaxRequests = 2 |
| EmailVerificationDuration = 30 |
| ) |
|
|
| func redisEmailVerificationRateLimiter(c *gin.Context) { |
| ctx := context.Background() |
| rdb := common.RDB |
| key := "emailVerification:" + EmailVerificationRateLimitMark + ":" + c.ClientIP() |
|
|
| count, err := rdb.Incr(ctx, key).Result() |
| if err != nil { |
| |
| memoryEmailVerificationRateLimiter(c) |
| return |
| } |
|
|
| |
| if count == 1 { |
| _ = rdb.Expire(ctx, key, time.Duration(EmailVerificationDuration)*time.Second).Err() |
| } |
|
|
| |
| if count <= int64(EmailVerificationMaxRequests) { |
| c.Next() |
| return |
| } |
|
|
| |
| ttl, err := rdb.TTL(ctx, key).Result() |
| waitSeconds := int64(EmailVerificationDuration) |
| if err == nil && ttl > 0 { |
| waitSeconds = int64(ttl.Seconds()) |
| } |
|
|
| c.JSON(http.StatusTooManyRequests, gin.H{ |
| "success": false, |
| "message": fmt.Sprintf("发送过于频繁,请等待 %d 秒后再试", waitSeconds), |
| }) |
| c.Abort() |
| } |
|
|
| func memoryEmailVerificationRateLimiter(c *gin.Context) { |
| key := EmailVerificationRateLimitMark + ":" + c.ClientIP() |
|
|
| if !inMemoryRateLimiter.Request(key, EmailVerificationMaxRequests, EmailVerificationDuration) { |
| c.JSON(http.StatusTooManyRequests, gin.H{ |
| "success": false, |
| "message": "发送过于频繁,请稍后再试", |
| }) |
| c.Abort() |
| return |
| } |
|
|
| c.Next() |
| } |
|
|
| func EmailVerificationRateLimit() gin.HandlerFunc { |
| return func(c *gin.Context) { |
| if common.RedisEnabled { |
| redisEmailVerificationRateLimiter(c) |
| } else { |
| inMemoryRateLimiter.Init(common.RateLimitKeyExpirationDuration) |
| memoryEmailVerificationRateLimiter(c) |
| } |
| } |
| } |
|
|