feat: 密码错误时禁用token并每3秒输出一次提示

This commit is contained in:
ShenQiLun 2026-06-30 11:46:14 +08:00
parent 8ae1ded87f
commit f7efcc5378
3 changed files with 75 additions and 0 deletions

View File

@ -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查询记录 // GetByID 根据ID查询记录
func (r *GoodsRepository) GetByID(id int64) (*GoodsPricing, error) { 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 = ?` query := `SELECT id, isbn, out_id, quality, query_index, user_id, price, shipping_fee FROM goods_pricing WHERE id = ?`

View File

@ -27,6 +27,11 @@ type GoodsService struct {
tokenRepository *repository.TokenRepository tokenRepository *repository.TokenRepository
currentTokenIndex int currentTokenIndex int
tokenMu sync.Mutex tokenMu sync.Mutex
badPasswords map[string]bool
badPWMu sync.Mutex
alertStartedMu sync.Mutex
alertStarted bool
} }
// NewGoodsService 创建商品服务实例 // NewGoodsService 创建商品服务实例
@ -38,6 +43,7 @@ func NewGoodsService(proxy string, apiRateLimitSeconds int, callbackURL string,
callbackURL: callbackURL, callbackURL: callbackURL,
tokenRepository: tokenRepo, tokenRepository: tokenRepo,
currentTokenIndex: 0, 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 启动定时器 // StartTimerScheduler 启动定时器
func (s *GoodsService) StartTimerScheduler(intervalSeconds int) { func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
log.Printf("[TimerScheduler] 定时器启动, 间隔=%d秒", intervalSeconds) 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) log.Printf("[outGetAllGoods] Token已失效, 尝试自动重新登录: username=%s, id=%d", tokenRecord.Username, tokenRecord.ID)
newToken, refreshErr := s.TryRefreshToken(tokenRecord.ID, tokenRecord.Username, tokenRecord.Password) newToken, refreshErr := s.TryRefreshToken(tokenRecord.ID, tokenRecord.Username, tokenRecord.Password)
if refreshErr != nil { if refreshErr != nil {
if refreshErr == ErrPasswordWrong {
s.goodsRepository.DisableToken(tokenRecord.ID)
s.reportBadPassword(tokenRecord.Username)
return nil, refreshErr
}
log.Printf("[outGetAllGoods] 自动重新登录失败: %v", refreshErr) log.Printf("[outGetAllGoods] 自动重新登录失败: %v", refreshErr)
return nil, err return nil, err
} }

View File

@ -2,6 +2,7 @@ package service
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
@ -11,6 +12,9 @@ import (
"github.com/parnurzeal/gorequest" "github.com/parnurzeal/gorequest"
) )
// ErrPasswordWrong 账号或密码错误,不再重试
var ErrPasswordWrong = errors.New("孔网账号或密码错误")
// UserInfo 孔网用户信息结构体 // UserInfo 孔网用户信息结构体
type UserInfo struct { type UserInfo struct {
UserID int64 `json:"userId"` // 用户ID UserID int64 `json:"userId"` // 用户ID
@ -127,11 +131,15 @@ func OutKfzGetUserInfo(token string) (*UserInfo, error) {
} }
// TryRefreshToken 尝试用保存的密码重新登录更新token。成功返回新token // TryRefreshToken 尝试用保存的密码重新登录更新token。成功返回新token
// 密码错误时返回 ErrPasswordWrong
func (s *GoodsService) TryRefreshToken(tokenID int64, username, password string) (string, error) { func (s *GoodsService) TryRefreshToken(tokenID int64, username, password string) (string, error) {
log.Printf("[RefreshToken] 开始重新登录: username=%s, tokenID=%d", username, tokenID) log.Printf("[RefreshToken] 开始重新登录: username=%s, tokenID=%d", username, tokenID)
newToken, err := OutKfzLogin(username, password) newToken, err := OutKfzLogin(username, password)
if err != nil { if err != nil {
log.Printf("[RefreshToken] 重新登录失败: username=%s, 错误=%v", username, err) log.Printf("[RefreshToken] 重新登录失败: username=%s, 错误=%v", username, err)
if strings.Contains(err.Error(), "账号或密码错误") {
return "", ErrPasswordWrong
}
return "", err return "", err
} }
// 更新数据库中的token // 更新数据库中的token