diff --git a/auth/session.go b/auth/session.go new file mode 100644 index 0000000..1bd1854 --- /dev/null +++ b/auth/session.go @@ -0,0 +1,94 @@ +// auth/session.go +package auth + +import ( + "crypto/rand" + "encoding/hex" + "sync" + "time" +) + +type Session struct { + ID string + CreatedAt time.Time + ExpiresAt time.Time + LastSeen time.Time +} + +type SessionManager struct { + sessions sync.Map + timeout time.Duration + mu sync.Mutex +} + +func NewSessionManager(timeout time.Duration) *SessionManager { + sm := &SessionManager{ + timeout: timeout, + } + + // 启动清理协程 + go sm.cleanup() + + return sm +} + +func (sm *SessionManager) Create(timeout time.Duration) string { + id := generateSecureToken() + now := time.Now() + + sm.sessions.Store(id, &Session{ + ID: id, + CreatedAt: now, + ExpiresAt: now.Add(timeout), + LastSeen: now, + }) + + return id +} + +func (sm *SessionManager) Valid(id string) bool { + val, ok := sm.sessions.Load(id) + if !ok { + return false + } + + session := val.(*Session) + now := time.Now() + + if now.After(session.ExpiresAt) { + sm.sessions.Delete(id) + return false + } + + // 更新最后活动时间和过期时间 + session.LastSeen = now + session.ExpiresAt = now.Add(sm.timeout) + + return true +} + +func (sm *SessionManager) Delete(id string) { + sm.sessions.Delete(id) +} + +func (sm *SessionManager) cleanup() { + ticker := time.NewTicker(5 * time.Minute) + defer ticker.Stop() + + for range ticker.C { + now := time.Now() + sm.sessions.Range(func(key, value interface{}) bool { + session := value.(*Session) + if now.After(session.ExpiresAt) { + sm.sessions.Delete(key) + } + return true + }) + } +} + +func generateSecureToken() string { + b := make([]byte, 32) + rand.Read(b) + return hex.EncodeToString(b) +}