accounts/rag-server/internal/auth/cache.go
Haitao Pan 96e4c8d719 feat(auth): implement rag-server remote auth middleware
Implement complete authentication middleware for rag-server:
- Remote token verification via accounts-service
- 60s TTL cache with background GC
- Gin middleware integration
- Role-based access control
- Zero-trust architecture (no private keys)
- Health check endpoint

Files:
- internal/auth/client.go (350 lines)
- internal/auth/middleware_verify.go (280 lines)
- internal/auth/cache.go (180 lines)
- internal/auth/example_test.go (150 lines)
- internal/auth/README.md (550 lines)
- cmd/xcontrol-server/main.go (updated)
- config/config.go (added AuthCfg)
- config/server.yaml (removed secrets)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-11-05 21:01:20 +08:00

175 lines
3.2 KiB
Go

package auth
import (
"sync"
"time"
)
// CacheEntry 缓存条目
type CacheEntry struct {
Value *TokenVerifyResponse
ExpiresAt time.Time
}
// TokenCache Token 验证结果缓存
type TokenCache struct {
mu sync.RWMutex
cache map[string]*CacheEntry
gcInterval time.Duration
ttl time.Duration
quit chan struct{}
}
// Config 缓存配置
type CacheConfig struct {
TTL time.Duration // 默认 60s
GCInterval time.Duration // 垃圾回收间隔,默认 5m
InitialSize int // 初始容量,默认 100
}
// DefaultCacheConfig 返回默认缓存配置
func DefaultCacheConfig() *CacheConfig {
return &CacheConfig{
TTL: 60 * time.Second,
GCInterval: 5 * time.Minute,
InitialSize: 100,
}
}
// NewTokenCache 创建新的 Token 缓存
func NewTokenCache(cfg *CacheConfig) *TokenCache {
if cfg == nil {
cfg = DefaultCacheConfig()
}
if cfg.TTL == 0 {
cfg.TTL = 60 * time.Second
}
if cfg.GCInterval == 0 {
cfg.GCInterval = 5 * time.Minute
}
if cfg.InitialSize == 0 {
cfg.InitialSize = 100
}
cache := &TokenCache{
cache: make(map[string]*CacheEntry, cfg.InitialSize),
gcInterval: cfg.GCInterval,
ttl: cfg.TTL,
quit: make(chan struct{}),
}
// 启动后台 GC 任务
go cache.gcWorker()
return cache
}
// Get 获取缓存的验证结果
func (c *TokenCache) Get(token string) (*TokenVerifyResponse, bool) {
c.mu.RLock()
entry, exists := c.cache[token]
c.mu.RUnlock()
if !exists {
return nil, false
}
// 检查是否过期
if time.Now().After(entry.ExpiresAt) {
// 异步删除过期条目
go c.Delete(token)
return nil, false
}
return entry.Value, true
}
// Set 设置缓存
func (c *TokenCache) Set(token string, value *TokenVerifyResponse) {
c.mu.Lock()
c.cache[token] = &CacheEntry{
Value: value,
ExpiresAt: time.Now().Add(c.ttl),
}
c.mu.Unlock()
}
// Delete 删除缓存
func (c *TokenCache) Delete(token string) {
c.mu.Lock()
delete(c.cache, token)
c.mu.Unlock()
}
// Clear 清空缓存
func (c *TokenCache) Clear() {
c.mu.Lock()
for key := range c.cache {
delete(c.cache, key)
}
c.mu.Unlock()
}
// Size 返回缓存大小
func (c *TokenCache) Size() int {
c.mu.RLock()
size := len(c.cache)
c.mu.RUnlock()
return size
}
// Stop 停止缓存清理任务
func (c *TokenCache) Stop() {
close(c.quit)
}
// gcWorker 后台垃圾回收工作协程
func (c *TokenCache) gcWorker() {
ticker := time.NewTicker(c.gcInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
c.gc()
case <-c.quit:
return
}
}
}
// gc 清理过期缓存
func (c *TokenCache) gc() {
now := time.Now()
c.mu.Lock()
for token, entry := range c.cache {
if now.After(entry.ExpiresAt) {
delete(c.cache, token)
}
}
c.mu.Unlock()
}
// Stats 缓存统计信息
type CacheStats struct {
Size int `json:"size"`
TTL time.Duration `json:"ttl"`
GCInterval time.Duration `json:"gc_interval"`
HitCount int64 `json:"hit_count"`
MissCount int64 `json:"miss_count"`
EvictionCount int64 `json:"eviction_count"`
}
// Stats 返回缓存统计信息
func (c *TokenCache) Stats() CacheStats {
return CacheStats{
Size: c.Size(),
TTL: c.ttl,
GCInterval: c.gcInterval,
}
}