Files
smart-go/internal/auth/session/store.go
T
2026-04-23 18:58:13 +08:00

77 lines
1.7 KiB
Go

package session
import (
"context"
"encoding/json"
"errors"
"time"
"giter.top/smart/pkg/config"
"giter.top/smart/pkg/security"
"github.com/redis/go-redis/v9"
)
// ErrInvalidSession 会话不存在或已过期。
var ErrInvalidSession = errors.New("session: invalid or expired")
const redisKeyPrefix = "auth:sess:"
type payload struct {
UserID string `json:"user_id"`
TenantID string `json:"tenant_id"`
}
// Store Redis 会话(供 OAuth authorize 与登出)。
type Store struct {
rdb redis.UniversalClient
cfg *config.Config
}
// NewStore 创建会话存储。
func NewStore(rdb redis.UniversalClient, cfg *config.Config) *Store {
return &Store{rdb: rdb, cfg: cfg}
}
func (s *Store) ttl() time.Duration {
t := s.cfg.Auth.Session.TTL
if t == 0 {
return 168 * time.Hour
}
return t
}
// Create 创建会话并返回 session id(写入 Cookie 用)。
func (s *Store) Create(ctx context.Context, userID, tenantID string) (sid string, err error) {
sid, err = security.RandomURLSafe(32)
if err != nil {
return "", err
}
b, err := json.Marshal(payload{UserID: userID, TenantID: tenantID})
if err != nil {
return "", err
}
return sid, s.rdb.Set(ctx, redisKeyPrefix+sid, b, s.ttl()).Err()
}
// Get 解析会话。
func (s *Store) Get(ctx context.Context, sid string) (userID, tenantID string, err error) {
b, err := s.rdb.Get(ctx, redisKeyPrefix+sid).Bytes()
if err == redis.Nil {
return "", "", ErrInvalidSession
}
if err != nil {
return "", "", err
}
var p payload
if err := json.Unmarshal(b, &p); err != nil {
return "", "", ErrInvalidSession
}
return p.UserID, p.TenantID, nil
}
// Delete 登出时删除。
func (s *Store) Delete(ctx context.Context, sid string) error {
return s.rdb.Del(ctx, redisKeyPrefix+sid).Err()
}