feat: add redis huohanhan auth cache

This commit is contained in:
QiuSW
2026-09-14 10:24:15 +08:00
parent 3fce4c6124
commit f8c90004f1
7 changed files with 113 additions and 1 deletions
+3
View File
@@ -35,6 +35,9 @@ func (e ShopeeProduct) newHuohanhanClient() (*huohanhan.Client, error) {
}
cfg := config.HuohanhanConfig{BaseURL: ext.ExtConfig.Huohanhan.BaseURL, Account: ext.ExtConfig.Huohanhan.Account, Password: ext.ExtConfig.Huohanhan.Password, OCRURL: ext.ExtConfig.Huohanhan.OCRURL}
logger := logx.New(1000)
if redisState, _ := huohanhan.NewRedisStateStore(ext.ExtConfig.Redis.Addr, ext.ExtConfig.Redis.Password, ext.ExtConfig.Redis.DB, time.Duration(ext.ExtConfig.Redis.AuthTTLSeconds)*time.Second); redisState != nil {
state = huohanhan.NewCachedStateStore(redisState, state)
}
auth := huohanhan.NewAuthManager(cfg, state, logger, huohanhan.AuthOptions{})
return huohanhan.NewClient(cfg, auth, logger, nil)
}
+6 -1
View File
@@ -47,11 +47,16 @@ settings:
# 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径
frontpath: ../go-admin-ui/src
extend: # 扩展项使用说明
huohanhan:
huohanhan:
base_url: https://www.huohanhan.com
account: ""
password: ""
ocr_url: https://ocr.ilapage.cn/ocr
redis:
addr: 127.0.0.1:6379
password: ""
db: 0
auth_ttl_seconds: 86400
demo:
name: data
cache:
+7
View File
@@ -5,6 +5,13 @@ var ExtConfig Extend
type Extend struct {
AMap AMap `yaml:"demo" json:"demo"`
Huohanhan HuohanhanConfig `yaml:"huohanhan" json:"huohanhan"`
Redis RedisConfig `yaml:"redis" json:"redis"`
}
type RedisConfig struct {
Addr string `yaml:"addr" json:"addr"`
Password string `yaml:"password" json:"password"`
DB int `yaml:"db" json:"db"`
AuthTTLSeconds int `yaml:"auth_ttl_seconds" json:"auth_ttl_seconds"`
}
type AMap struct {
Key string `yaml:"key" json:"key"`
+2
View File
@@ -112,6 +112,7 @@ require (
github.com/prometheus/procfs v0.21.1 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.61.0 // indirect
github.com/redis/go-redis/v9 v9.22.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/shamsher31/goimgext v1.0.0 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
@@ -124,6 +125,7 @@ require (
github.com/ugorji/go/codec v1.3.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
+4
View File
@@ -476,6 +476,8 @@ github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9q
github.com/quic-go/quic-go v0.61.0 h1:ui88A53s8MSVYLC56en0KQ17HARk+9986Dn0SBfKNvA=
github.com/quic-go/quic-go v0.61.0/go.mod h1:9So2anK4Tp22URSQq00k+Vo2PNkle96ycDPDHL4s9vs=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.22.0 h1:laDvpYXTJtZLloinw1fA5Kqd6HAEH2XKxOkG/PDq2F0=
github.com/redis/go-redis/v9 v9.22.0/go.mod h1:y2g0Wj8rQvuK0ELM+oxSudcLtC09JScs98I/X9gRWY4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
@@ -583,6 +585,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+66
View File
@@ -0,0 +1,66 @@
package huohanhan
import (
"context"
"github.com/redis/go-redis/v9"
"time"
)
type RedisStateStore struct {
client *redis.Client
prefix string
ttl time.Duration
}
type CachedStateStore struct {
cache *RedisStateStore
durable StateStore
}
func NewCachedStateStore(cache *RedisStateStore, durable StateStore) StateStore {
return &CachedStateStore{cache: cache, durable: durable}
}
func NewRedisStateStore(addr, password string, db int, ttl time.Duration) (*RedisStateStore, error) {
if addr == "" {
return nil, nil
}
if ttl <= 0 {
ttl = 24 * time.Hour
}
return &RedisStateStore{client: redis.NewClient(&redis.Options{Addr: addr, Password: password, DB: db}), prefix: "erpgo:huohanhan:", ttl: ttl}, nil
}
func (s *RedisStateStore) SetKV(key, value, _ string) error {
return s.client.Set(context.Background(), s.prefix+key, value, s.ttl).Err()
}
func (s *RedisStateStore) GetKV(key string) (string, bool, error) {
v, err := s.client.Get(context.Background(), s.prefix+key).Result()
if err == redis.Nil {
return "", false, nil
}
return v, err == nil, err
}
func (s *RedisStateStore) Delete(key string) error {
return s.client.Del(context.Background(), s.prefix+key).Err()
}
func (s *RedisStateStore) Close() error { return s.client.Close() }
func (s *CachedStateStore) SetKV(key, value, now string) error {
if err := s.durable.SetKV(key, value, now); err != nil {
return err
}
if value == "" {
_ = s.cache.Delete(key)
} else {
_ = s.cache.SetKV(key, value, now)
}
return nil
}
func (s *CachedStateStore) GetKV(key string) (string, bool, error) {
if v, ok, err := s.cache.GetKV(key); err == nil && ok && v != "" {
return v, true, nil
}
v, ok, err := s.durable.GetKV(key)
if err == nil && ok && v != "" {
_ = s.cache.SetKV(key, v, "")
}
return v, ok && v != "", err
}
@@ -0,0 +1,25 @@
# LOCAL-010:Redis 缓存货憨憨认证状态
- 状态:进行中
- 来源:用户需求(2026-09-14)
- 前置:LOCAL-009
## 目标
使用 Redis 缓存货憨憨 token 和 Cookie,减少每次商品请求的在线校验;MySQL 保留持久化状态和恢复来源。
## 规则
- Redis 认证状态默认 TTL 24 小时;
- Redis 没有状态时从 MySQL 恢复,仍无状态才登录;
- 货憨憨请求返回认证失效时删除 Redis 状态,重新登录并重试一次;
- Redis 不可用时自动回退 MySQL;
- 不记录 token、Cookie 或 Redis 内容到日志。
## 验收
- Redis 命中时不再额外调用货憨憨在线校验;
- Redis 过期或清空后可以从 MySQL 恢复;
- 认证失效会清除缓存并重新登录;
- Redis 不可用不影响现有 MySQL 流程;
- 相关测试通过。