From f7efcc53785a465970b1df8b2d073876b29750e1 Mon Sep 17 00:00:00 2001 From: ShenQiLun <97694732@qq.com> Date: Tue, 30 Jun 2026 11:46:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=86=E7=A0=81=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=97=B6=E7=A6=81=E7=94=A8token=E5=B9=B6=E6=AF=8F3=E7=A7=92?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E4=B8=80=E6=AC=A1=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/repository/goods_repository.go | 11 +++++ internal/service/goods_service.go | 56 +++++++++++++++++++++++++ internal/service/kfz_service.go | 8 ++++ 3 files changed, 75 insertions(+) diff --git a/internal/repository/goods_repository.go b/internal/repository/goods_repository.go index 9fb5d26..00b3767 100644 --- a/internal/repository/goods_repository.go +++ b/internal/repository/goods_repository.go @@ -80,6 +80,17 @@ func (r *GoodsRepository) MarkFailed(id int64) { } } +// DisableToken 禁用Token(设置is_enable=0) +func (r *GoodsRepository) DisableToken(id int64) { + query := `UPDATE kfz_token SET is_enable = 0 WHERE id = ?` + _, err := database.DB.Exec(query, id) + if err != nil { + log.Printf("[Repo/Goods] 禁用Token失败: id=%d, 错误=%v", id, err) + } else { + log.Printf("[Repo/Goods] 禁用Token成功: id=%d", id) + } +} + // GetByID 根据ID查询记录 func (r *GoodsRepository) GetByID(id int64) (*GoodsPricing, error) { query := `SELECT id, isbn, out_id, quality, query_index, user_id, price, shipping_fee FROM goods_pricing WHERE id = ?` diff --git a/internal/service/goods_service.go b/internal/service/goods_service.go index 76ea09a..581523b 100644 --- a/internal/service/goods_service.go +++ b/internal/service/goods_service.go @@ -27,6 +27,11 @@ type GoodsService struct { tokenRepository *repository.TokenRepository currentTokenIndex int tokenMu sync.Mutex + + badPasswords map[string]bool + badPWMu sync.Mutex + alertStartedMu sync.Mutex + alertStarted bool } // NewGoodsService 创建商品服务实例 @@ -38,6 +43,7 @@ func NewGoodsService(proxy string, apiRateLimitSeconds int, callbackURL string, callbackURL: callbackURL, tokenRepository: tokenRepo, currentTokenIndex: 0, + badPasswords: make(map[string]bool), } } @@ -137,6 +143,51 @@ func (s *GoodsService) sendCallback(outID, userID string, price, shippingFee flo } } +// reportBadPassword 记录密码错误并启动每3秒输出一次提示 +func (s *GoodsService) reportBadPassword(username string) { + s.badPWMu.Lock() + if s.badPasswords[username] { + s.badPWMu.Unlock() + return + } + s.badPasswords[username] = true + s.badPWMu.Unlock() + + log.Printf("[BadPassword] 孔网账号密码错误: username=%s, 已禁用该token, 每3秒输出一次提示", username) + + s.alertStartedMu.Lock() + if s.alertStarted { + s.alertStartedMu.Unlock() + return + } + s.alertStarted = true + s.alertStartedMu.Unlock() + + go func() { + ticker := time.NewTicker(3 * time.Second) + defer ticker.Stop() + for range ticker.C { + s.badPWMu.Lock() + if len(s.badPasswords) == 0 { + s.badPWMu.Unlock() + s.alertStartedMu.Lock() + s.alertStarted = false + s.alertStartedMu.Unlock() + return + } + users := make([]string, 0, len(s.badPasswords)) + for u := range s.badPasswords { + users = append(users, u) + } + s.badPWMu.Unlock() + + for _, u := range users { + log.Printf("[BadPassword] 孔网账号或密码错误: username=%s, 请更新密码后重新登录", u) + } + } + }() +} + // StartTimerScheduler 启动定时器 func (s *GoodsService) StartTimerScheduler(intervalSeconds int) { log.Printf("[TimerScheduler] 定时器启动, 间隔=%d秒", intervalSeconds) @@ -298,6 +349,11 @@ func (s *GoodsService) doKfzSearch(kfzUrl, token string, tokenRecord *repository log.Printf("[outGetAllGoods] Token已失效, 尝试自动重新登录: username=%s, id=%d", tokenRecord.Username, tokenRecord.ID) newToken, refreshErr := s.TryRefreshToken(tokenRecord.ID, tokenRecord.Username, tokenRecord.Password) if refreshErr != nil { + if refreshErr == ErrPasswordWrong { + s.goodsRepository.DisableToken(tokenRecord.ID) + s.reportBadPassword(tokenRecord.Username) + return nil, refreshErr + } log.Printf("[outGetAllGoods] 自动重新登录失败: %v", refreshErr) return nil, err } diff --git a/internal/service/kfz_service.go b/internal/service/kfz_service.go index 0dcef9f..de0a12e 100644 --- a/internal/service/kfz_service.go +++ b/internal/service/kfz_service.go @@ -2,6 +2,7 @@ package service import ( "encoding/json" + "errors" "fmt" "log" "net/http" @@ -11,6 +12,9 @@ import ( "github.com/parnurzeal/gorequest" ) +// ErrPasswordWrong 账号或密码错误,不再重试 +var ErrPasswordWrong = errors.New("孔网账号或密码错误") + // UserInfo 孔网用户信息结构体 type UserInfo struct { UserID int64 `json:"userId"` // 用户ID @@ -127,11 +131,15 @@ func OutKfzGetUserInfo(token string) (*UserInfo, error) { } // TryRefreshToken 尝试用保存的密码重新登录,更新token。成功返回新token +// 密码错误时返回 ErrPasswordWrong func (s *GoodsService) TryRefreshToken(tokenID int64, username, password string) (string, error) { log.Printf("[RefreshToken] 开始重新登录: username=%s, tokenID=%d", username, tokenID) newToken, err := OutKfzLogin(username, password) if err != nil { log.Printf("[RefreshToken] 重新登录失败: username=%s, 错误=%v", username, err) + if strings.Contains(err.Error(), "账号或密码错误") { + return "", ErrPasswordWrong + } return "", err } // 更新数据库中的token