修复:调整游客取号限流策略

问题:移动网络共享出口 IP 会造成游客取号被误限流。

实现:移除公开取号 IP 限制,改用项目总量与手机号 HMAC 限流,并支持 Retry-After 倒计时。
This commit is contained in:
2026-07-31 22:56:33 +08:00
parent 3f4a9bf398
commit c2a5281534
17 changed files with 357 additions and 73 deletions

View File

@@ -12,22 +12,25 @@ import (
)
type Config struct {
Environment string
HTTPAddr string
DatabaseURL string
EncryptionKey []byte
PhoneHMACKey []byte
SessionCookieName string
SessionSecure bool
SessionTTL time.Duration
MigrateOnStart bool
ShutdownTimeout time.Duration
DBMaxOpenConns int
DBMaxIdleConns int
DBConnMaxIdleTime time.Duration
DBConnMaxLifetime time.Duration
MaintenanceInterval time.Duration
MaintenanceBatchSize int
Environment string
HTTPAddr string
DatabaseURL string
EncryptionKey []byte
PhoneHMACKey []byte
SessionCookieName string
SessionSecure bool
SessionTTL time.Duration
MigrateOnStart bool
ShutdownTimeout time.Duration
DBMaxOpenConns int
DBMaxIdleConns int
DBConnMaxIdleTime time.Duration
DBConnMaxLifetime time.Duration
MaintenanceInterval time.Duration
MaintenanceBatchSize int
PublicTicketProjectLimit int
PublicTicketPhoneLimit int
PublicTicketRateWindow time.Duration
}
func Load() (Config, error) {
@@ -100,6 +103,18 @@ func load(lookup func(string) (string, bool)) (Config, error) {
if err != nil {
return Config{}, err
}
publicTicketProjectLimit, err := parseIntSetting("PUBLIC_TICKET_PROJECT_LIMIT", get("PUBLIC_TICKET_PROJECT_LIMIT", "1000"), 1, 1000000)
if err != nil {
return Config{}, err
}
publicTicketPhoneLimit, err := parseIntSetting("PUBLIC_TICKET_PHONE_LIMIT", get("PUBLIC_TICKET_PHONE_LIMIT", "5"), 1, 10000)
if err != nil {
return Config{}, err
}
publicTicketRateWindow, err := parseDurationSetting("PUBLIC_TICKET_RATE_WINDOW", get("PUBLIC_TICKET_RATE_WINDOW", "1m"), time.Second, time.Hour)
if err != nil {
return Config{}, err
}
if environment == "production" && !sessionSecure {
return Config{}, errors.New("SESSION_COOKIE_SECURE must be true in production")
}
@@ -119,22 +134,25 @@ func load(lookup func(string) (string, bool)) (Config, error) {
}
return Config{
Environment: environment,
HTTPAddr: get("HTTP_ADDR", ":8080"),
DatabaseURL: databaseURL,
EncryptionKey: encryptionKey,
PhoneHMACKey: phoneHMACKey,
SessionCookieName: cookieName,
SessionSecure: sessionSecure,
SessionTTL: sessionTTL,
MigrateOnStart: migrate,
ShutdownTimeout: shutdownTimeout,
DBMaxOpenConns: maxOpen,
DBMaxIdleConns: maxIdle,
DBConnMaxIdleTime: connMaxIdleTime,
DBConnMaxLifetime: connMaxLifetime,
MaintenanceInterval: maintenanceInterval,
MaintenanceBatchSize: maintenanceBatchSize,
Environment: environment,
HTTPAddr: get("HTTP_ADDR", ":8080"),
DatabaseURL: databaseURL,
EncryptionKey: encryptionKey,
PhoneHMACKey: phoneHMACKey,
SessionCookieName: cookieName,
SessionSecure: sessionSecure,
SessionTTL: sessionTTL,
MigrateOnStart: migrate,
ShutdownTimeout: shutdownTimeout,
DBMaxOpenConns: maxOpen,
DBMaxIdleConns: maxIdle,
DBConnMaxIdleTime: connMaxIdleTime,
DBConnMaxLifetime: connMaxLifetime,
MaintenanceInterval: maintenanceInterval,
MaintenanceBatchSize: maintenanceBatchSize,
PublicTicketProjectLimit: publicTicketProjectLimit,
PublicTicketPhoneLimit: publicTicketPhoneLimit,
PublicTicketRateWindow: publicTicketRateWindow,
}, nil
}