公开密码登录口按 IP 限制 10 分钟内最多 20 次失败,堵住未授权爆破。metric 持平 8。

Result: {"status":"keep","total_issues":8,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"measure_s":85,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_usetesting":0,"golint_test_total":0,"golint_exhaustive":0,"golint_vetx_total":0,"vitest_failed":0,"vitest_total":126}
This commit is contained in:
ryan
2026-08-25 23:11:05 +08:00
parent c9fc9c0eea
commit d73aa5f9f0
4 changed files with 52 additions and 0 deletions
+42
View File
@@ -13,6 +13,7 @@ import (
"fmt"
"math/big"
"strings"
"time"
"github.com/Rain-kl/Wavelet/internal/apps/oauth"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
@@ -51,6 +52,47 @@ type updateProfileInput struct {
Location string
}
const (
loginFailLimitKeyFormat = "login:fail:%s"
loginFailLimitMax = 20
loginFailLimitWindow = 10 * time.Minute
)
func loginFailLimitKey(ip string) string {
return fmt.Sprintf(loginFailLimitKeyFormat, strings.TrimSpace(ip))
}
func loginAttemptsBlocked(ctx context.Context, ip string) bool {
if db.Redis == nil {
return false
}
n, err := db.Redis.Get(ctx, db.PrefixedKey(loginFailLimitKey(ip))).Int()
if err != nil {
return false
}
return n >= loginFailLimitMax
}
func recordFailedLogin(ctx context.Context, ip string) {
if db.Redis == nil {
return
}
key := db.PrefixedKey(loginFailLimitKey(ip))
n, err := db.Redis.Incr(ctx, key).Result()
if err != nil {
return
}
if n == 1 {
_ = db.Redis.Expire(ctx, key, loginFailLimitWindow).Err()
}
}
func clearFailedLogins(ctx context.Context, ip string) {
if db.Redis == nil {
return
}
_ = db.Redis.Del(ctx, db.PrefixedKey(loginFailLimitKey(ip))).Err()
}
func isPasswordLoginEnabled(ctx context.Context) bool {
enabled, err := repository.GetBoolByKey(ctx, model.ConfigKeyPasswordLoginEnabled)
if err != nil {