feat: kfz_token表增加login_name字段, 存储孔网登录账号

This commit is contained in:
ShenQiLun 2026-06-30 13:27:19 +08:00
parent 6c1e016672
commit fc9bd41b6d
6 changed files with 2200 additions and 53 deletions

View File

@ -70,6 +70,7 @@ func createTables() error {
CREATE TABLE IF NOT EXISTS kfz_token ( CREATE TABLE IF NOT EXISTS kfz_token (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
login_name TEXT NOT NULL DEFAULT '',
username TEXT NOT NULL, username TEXT NOT NULL,
password TEXT NOT NULL DEFAULT '', password TEXT NOT NULL DEFAULT '',
token TEXT NOT NULL, token TEXT NOT NULL,
@ -95,8 +96,9 @@ func createTables() error {
return err return err
} }
// 兼容旧表:添加 password 列(已存在则忽略) // 兼容旧表:添加 password / login_name 列(已存在则忽略)
DB.Exec(`ALTER TABLE kfz_token ADD COLUMN password TEXT NOT NULL DEFAULT ''`) DB.Exec(`ALTER TABLE kfz_token ADD COLUMN password TEXT NOT NULL DEFAULT ''`)
DB.Exec(`ALTER TABLE kfz_token ADD COLUMN login_name TEXT NOT NULL DEFAULT ''`)
return nil return nil
} }

View File

@ -61,10 +61,10 @@ func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
userInfo.Token = token userInfo.Token = token
// 保存账号密码和token到数据库 // 保存账号密码和token到数据库
if err := h.tokenRepo.UpsertByUsername(username, password, token); err != nil { if err := h.tokenRepo.UpsertByLoginName(username, userInfo.Nickname, password, token); err != nil {
log.Printf("[KfzLogin] 保存Token记录失败: err=%v, clientIP=%s", err, clientIP) log.Printf("[KfzLogin] 保存Token记录失败: err=%v, clientIP=%s", err, clientIP)
} else { } else {
log.Printf("[KfzLogin] 账号密码已保存到数据库: username=%s", username) log.Printf("[KfzLogin] 账号密码已保存到数据库: login_name=%s, nickname=%s", username, userInfo.Nickname)
} }
log.Printf("[KfzLogin] 登录成功: username=%s, userId=%d, nickname=%s, 来源IP: %s", username, userInfo.UserID, userInfo.Nickname, clientIP) log.Printf("[KfzLogin] 登录成功: username=%s, userId=%d, nickname=%s, 来源IP: %s", username, userInfo.UserID, userInfo.Nickname, clientIP)

View File

@ -71,7 +71,7 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
continue continue
} }
id, err := h.tokenRepo.Insert(input.Username, "", input.Token, true) id, err := h.tokenRepo.Insert("", input.Username, "", input.Token, true)
if err != nil { if err != nil {
log.Printf("[Token/BatchAdd] 第%d条插入失败: username=%s, 错误=%v", i+1, input.Username, err) log.Printf("[Token/BatchAdd] 第%d条插入失败: username=%s, 错误=%v", i+1, input.Username, err)
failed = append(failed, input) failed = append(failed, input)
@ -196,7 +196,7 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
} }
log.Printf("[Token/Update] 更新: id=%d, username=%s, is_enable=%v, 来源IP: %s", id, username, isEnable, clientIP) log.Printf("[Token/Update] 更新: id=%d, username=%s, is_enable=%v, 来源IP: %s", id, username, isEnable, clientIP)
err = h.tokenRepo.Update(id, username, "", token, isEnable) err = h.tokenRepo.Update(id, "", username, "", token, isEnable)
if err != nil { if err != nil {
log.Printf("[Token/Update] 更新失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP) log.Printf("[Token/Update] 更新失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@ -11,11 +11,12 @@ import (
// KfzToken Token记录 // KfzToken Token记录
type KfzToken struct { type KfzToken struct {
ID int64 ID int64
Username string LoginName string
Password string Username string
Token string Password string
IsEnable bool Token string
IsEnable bool
} }
// TokenRepository Token仓储 // TokenRepository Token仓储
@ -66,11 +67,11 @@ func (r *TokenRepository) BatchInsert(tokens []string, username string) (int64,
return id, nil return id, nil
} }
// Insert 插入单条Token记录(含密码) // Insert 插入单条Token记录
func (r *TokenRepository) Insert(username, password, token string, isEnable bool) (int64, error) { func (r *TokenRepository) Insert(loginName, username, password, token string, isEnable bool) (int64, error) {
query := `INSERT INTO kfz_token (username, password, token, is_enable) VALUES (?, ?, ?, ?)` query := `INSERT INTO kfz_token (login_name, username, password, token, is_enable) VALUES (?, ?, ?, ?, ?)`
result, err := database.DB.Exec(query, username, password, token, isEnable) result, err := database.DB.Exec(query, loginName, username, password, token, isEnable)
if err != nil { if err != nil {
return 0, fmt.Errorf("插入失败: %w", err) return 0, fmt.Errorf("插入失败: %w", err)
} }
@ -83,35 +84,35 @@ func (r *TokenRepository) Insert(username, password, token string, isEnable bool
return id, nil return id, nil
} }
// UpsertByUsername 根据用户名插入或更新记录含密码和token // UpsertByLoginName 根据登录名插入或更新记录
func (r *TokenRepository) UpsertByUsername(username, password, token string) error { func (r *TokenRepository) UpsertByLoginName(loginName, username, password, token string) error {
var count int var count int
err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_token WHERE username = ?", username).Scan(&count) err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_token WHERE login_name = ?", loginName).Scan(&count)
if err != nil { if err != nil {
return fmt.Errorf("查询记录失败: %w", err) return fmt.Errorf("查询记录失败: %w", err)
} }
if count == 0 { if count == 0 {
_, err = database.DB.Exec( _, err = database.DB.Exec(
`INSERT INTO kfz_token (username, password, token, is_enable) VALUES (?, ?, ?, 1)`, `INSERT INTO kfz_token (login_name, username, password, token, is_enable) VALUES (?, ?, ?, ?, 1)`,
username, password, token, loginName, username, password, token,
) )
} else { } else {
_, err = database.DB.Exec( _, err = database.DB.Exec(
`UPDATE kfz_token SET password = ?, token = ?, is_enable = 1 WHERE username = ?`, `UPDATE kfz_token SET username = ?, password = ?, token = ?, is_enable = 1 WHERE login_name = ?`,
password, token, username, username, password, token, loginName,
) )
} }
if err != nil { if err != nil {
return fmt.Errorf("保存Token记录失败: %w", err) return fmt.Errorf("保存Token记录失败: %w", err)
} }
log.Printf("[Repo/Token] 保存Token成功: username=%s", username) log.Printf("[Repo/Token] 保存Token成功: login_name=%s, username=%s", loginName, username)
return nil return nil
} }
// GetAll 查询所有记录 // GetAll 查询所有记录
func (r *TokenRepository) GetAll() ([]*KfzToken, error) { func (r *TokenRepository) GetAll() ([]*KfzToken, error) {
query := `SELECT id, username, token, is_enable FROM kfz_token ORDER BY id ASC` query := `SELECT id, login_name, username, token, is_enable FROM kfz_token ORDER BY id ASC`
rows, err := database.DB.Query(query) rows, err := database.DB.Query(query)
if err != nil { if err != nil {
@ -122,7 +123,7 @@ func (r *TokenRepository) GetAll() ([]*KfzToken, error) {
var records []*KfzToken var records []*KfzToken
for rows.Next() { for rows.Next() {
var rec KfzToken var rec KfzToken
err := rows.Scan(&rec.ID, &rec.Username, &rec.Token, &rec.IsEnable) err := rows.Scan(&rec.ID, &rec.LoginName, &rec.Username, &rec.Token, &rec.IsEnable)
if err != nil { if err != nil {
return nil, fmt.Errorf("扫描失败: %w", err) return nil, fmt.Errorf("扫描失败: %w", err)
} }
@ -134,12 +135,12 @@ func (r *TokenRepository) GetAll() ([]*KfzToken, error) {
// GetByID 根据ID查询单条记录 // GetByID 根据ID查询单条记录
func (r *TokenRepository) GetByID(id int64) (*KfzToken, error) { func (r *TokenRepository) GetByID(id int64) (*KfzToken, error) {
query := `SELECT id, username, password, token, is_enable FROM kfz_token WHERE id = ?` query := `SELECT id, login_name, username, password, token, is_enable FROM kfz_token WHERE id = ?`
row := database.DB.QueryRow(query, id) row := database.DB.QueryRow(query, id)
var rec KfzToken var rec KfzToken
err := row.Scan(&rec.ID, &rec.Username, &rec.Password, &rec.Token, &rec.IsEnable) err := row.Scan(&rec.ID, &rec.LoginName, &rec.Username, &rec.Password, &rec.Token, &rec.IsEnable)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, fmt.Errorf("记录不存在") return nil, fmt.Errorf("记录不存在")
@ -150,29 +151,11 @@ func (r *TokenRepository) GetByID(id int64) (*KfzToken, error) {
return &rec, nil return &rec, nil
} }
// GetByUsername 根据用户名查询记录(含密码)
func (r *TokenRepository) GetByUsername(username string) (*KfzToken, error) {
query := `SELECT id, username, password, token, is_enable FROM kfz_token WHERE username = ?`
row := database.DB.QueryRow(query, username)
var rec KfzToken
err := row.Scan(&rec.ID, &rec.Username, &rec.Password, &rec.Token, &rec.IsEnable)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, fmt.Errorf("查询失败: %w", err)
}
return &rec, nil
}
// Update 更新记录 // Update 更新记录
func (r *TokenRepository) Update(id int64, username, password, token string, isEnable bool) error { func (r *TokenRepository) Update(id int64, loginName, username, password, token string, isEnable bool) error {
query := `UPDATE kfz_token SET username = ?, password = ?, token = ?, is_enable = ? WHERE id = ?` query := `UPDATE kfz_token SET login_name = ?, username = ?, password = ?, token = ?, is_enable = ? WHERE id = ?`
result, err := database.DB.Exec(query, username, password, token, isEnable, id) result, err := database.DB.Exec(query, loginName, username, password, token, isEnable, id)
if err != nil { if err != nil {
return fmt.Errorf("更新失败: %w", err) return fmt.Errorf("更新失败: %w", err)
} }
@ -222,7 +205,7 @@ func (r *TokenRepository) Delete(id int64) error {
// GetEnabledTokens 获取所有启用状态的Token // GetEnabledTokens 获取所有启用状态的Token
func (r *TokenRepository) GetEnabledTokens() ([]*KfzToken, error) { func (r *TokenRepository) GetEnabledTokens() ([]*KfzToken, error) {
query := `SELECT id, username, password, token, is_enable FROM kfz_token WHERE is_enable = 1 ORDER BY id ASC` query := `SELECT id, login_name, username, password, token, is_enable FROM kfz_token WHERE is_enable = 1 ORDER BY id ASC`
rows, err := database.DB.Query(query) rows, err := database.DB.Query(query)
if err != nil { if err != nil {
@ -233,7 +216,7 @@ func (r *TokenRepository) GetEnabledTokens() ([]*KfzToken, error) {
var records []*KfzToken var records []*KfzToken
for rows.Next() { for rows.Next() {
var rec KfzToken var rec KfzToken
err := rows.Scan(&rec.ID, &rec.Username, &rec.Password, &rec.Token, &rec.IsEnable) err := rows.Scan(&rec.ID, &rec.LoginName, &rec.Username, &rec.Password, &rec.Token, &rec.IsEnable)
if err != nil { if err != nil {
return nil, fmt.Errorf("扫描失败: %w", err) return nil, fmt.Errorf("扫描失败: %w", err)
} }

View File

@ -289,7 +289,7 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
s.tokenMu.Unlock() s.tokenMu.Unlock()
token := tokens[currentIdx].Token token := tokens[currentIdx].Token
log.Printf("[outGetAllGoods] 使用token索引: index=%d, total=%d, username=%s", currentIdx, len(tokens), tokens[currentIdx].Username) log.Printf("[outGetAllGoods] 使用token索引: index=%d, total=%d, login_name=%s, nickname=%s", currentIdx, len(tokens), tokens[currentIdx].LoginName, tokens[currentIdx].Username)
kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2" kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2"
@ -346,12 +346,16 @@ func (s *GoodsService) doKfzSearch(kfzUrl, token string, tokenRecord *repository
errMsg := err.Error() errMsg := err.Error()
if strings.Contains(errMsg, "请登录") || strings.Contains(errMsg, "GO_LOGIN") || strings.Contains(errMsg, "errType=102") { if strings.Contains(errMsg, "请登录") || strings.Contains(errMsg, "GO_LOGIN") || strings.Contains(errMsg, "errType=102") {
if attempt == 1 && tokenRecord.Password != "" { if attempt == 1 && tokenRecord.Password != "" {
log.Printf("[outGetAllGoods] Token已失效, 尝试自动重新登录: username=%s, id=%d", tokenRecord.Username, tokenRecord.ID) loginName := tokenRecord.LoginName
newToken, refreshErr := s.TryRefreshToken(tokenRecord.ID, tokenRecord.Username, tokenRecord.Password) if loginName == "" {
loginName = tokenRecord.Username
}
log.Printf("[outGetAllGoods] Token已失效, 尝试自动重新登录: login_name=%s, nickname=%s, id=%d", loginName, tokenRecord.Username, tokenRecord.ID)
newToken, refreshErr := s.TryRefreshToken(tokenRecord.ID, loginName, tokenRecord.Password)
if refreshErr != nil { if refreshErr != nil {
if refreshErr == ErrPasswordWrong { if refreshErr == ErrPasswordWrong {
s.goodsRepository.DisableToken(tokenRecord.ID) s.goodsRepository.DisableToken(tokenRecord.ID)
s.reportBadPassword(tokenRecord.Username) s.reportBadPassword(loginName)
return nil, refreshErr return nil, refreshErr
} }
log.Printf("[outGetAllGoods] 自动重新登录失败: err=%v", refreshErr) log.Printf("[outGetAllGoods] 自动重新登录失败: err=%v", refreshErr)

File diff suppressed because it is too large Load Diff