first commit
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package redisdao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/redismodel"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// authTokenSAddScript 向用户 token 集合加入 refresh_token,仅在集合由空变为非空时设置 TTL,
|
||||
// 避免每次登录都刷新集合 TTL 导致旧 token 条目长期驻留。
|
||||
const authTokenSAddScript = `
|
||||
local added = redis.call('SADD', KEYS[1], ARGV[1])
|
||||
if added == 1 and redis.call('SCARD', KEYS[1]) == 1 then
|
||||
redis.call('EXPIRE', KEYS[1], ARGV[2])
|
||||
end
|
||||
return added
|
||||
`
|
||||
|
||||
// AuthTokenSet 登录成功后写入会话:
|
||||
// - access_token -> user_id
|
||||
// - refresh_token -> user_id
|
||||
// - user_id 的 token 集合加入 refresh_token(用于多端管理 / 登出)
|
||||
func AuthTokenSet(ctx context.Context, userID int64, accessToken, refreshToken string) error {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthTokenSet")
|
||||
defer span.End()
|
||||
|
||||
accessKey := fmt.Sprintf(redismodel.KeyAuthAccess, accessToken)
|
||||
refreshKey := fmt.Sprintf(redismodel.KeyAuthRefresh, refreshToken)
|
||||
userTokensKey := fmt.Sprintf(redismodel.KeyAuthUserTokens, userID)
|
||||
|
||||
accessTTL := time.Duration(global.JWTSetting.AccessTokenExpire) * time.Second
|
||||
refreshTTL := time.Duration(global.JWTSetting.RefreshTokenExpire) * time.Second
|
||||
|
||||
pipe := global.RedisEngine.TxPipeline()
|
||||
pipe.Set(ctx, accessKey, userID, accessTTL)
|
||||
pipe.Set(ctx, refreshKey, userID, refreshTTL)
|
||||
pipe.Eval(ctx, authTokenSAddScript, []string{userTokensKey}, refreshToken, int(refreshTTL.Seconds()))
|
||||
if _, err := pipe.Exec(ctx); err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthTokenDel 登出/失效:删除 access、refresh 映射,并从用户 token 集合移除 refresh_token
|
||||
func AuthTokenDel(ctx context.Context, userID int64, accessToken, refreshToken string) error {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthTokenDel")
|
||||
defer span.End()
|
||||
|
||||
accessKey := fmt.Sprintf(redismodel.KeyAuthAccess, accessToken)
|
||||
refreshKey := fmt.Sprintf(redismodel.KeyAuthRefresh, refreshToken)
|
||||
userTokensKey := fmt.Sprintf(redismodel.KeyAuthUserTokens, userID)
|
||||
|
||||
pipe := global.RedisEngine.TxPipeline()
|
||||
pipe.Del(ctx, accessKey)
|
||||
pipe.Del(ctx, refreshKey)
|
||||
pipe.SRem(ctx, userTokensKey, refreshToken)
|
||||
if _, err := pipe.Exec(ctx); err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthUserIDByAccess 通过 access token 查询 user_id,token 不存在或已过期返回 redis.Nil
|
||||
func AuthUserIDByAccess(ctx context.Context, accessToken string) (int64, error) {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthUserIDByAccess")
|
||||
defer span.End()
|
||||
|
||||
key := fmt.Sprintf(redismodel.KeyAuthAccess, accessToken)
|
||||
userID, err := global.RedisEngine.Get(ctx, key).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
span.RecordError(err)
|
||||
}
|
||||
return userID, err
|
||||
}
|
||||
|
||||
// AuthUserIDByRefresh 通过 refresh token 查询 user_id,token 不存在或已过期返回 redis.Nil
|
||||
func AuthUserIDByRefresh(ctx context.Context, refreshToken string) (int64, error) {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthUserIDByRefresh")
|
||||
defer span.End()
|
||||
|
||||
key := fmt.Sprintf(redismodel.KeyAuthRefresh, refreshToken)
|
||||
userID, err := global.RedisEngine.Get(ctx, key).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
span.RecordError(err)
|
||||
}
|
||||
return userID, err
|
||||
}
|
||||
|
||||
// sessionKeyTTL session_key 缓存时长(30 天,与微信 session_key 有效期对齐)。
|
||||
const sessionKeyTTL = 30 * 24 * time.Hour
|
||||
|
||||
// AuthSessionKeySet 写入用户的 session_key(登录时 code2session 返回,用于虚拟支付 signature 计算)。
|
||||
func AuthSessionKeySet(ctx context.Context, userID int64, sessionKey string) error {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthSessionKeySet")
|
||||
defer span.End()
|
||||
|
||||
key := fmt.Sprintf(redismodel.KeyAuthSessionKey, userID)
|
||||
if err := global.RedisEngine.Set(ctx, key, sessionKey, sessionKeyTTL).Err(); err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthSessionKeyGet 读取用户的 session_key,不存在返回 redis.Nil。
|
||||
func AuthSessionKeyGet(ctx context.Context, userID int64) (string, error) {
|
||||
ctx, span := global.Tracer.Start(ctx, "redisdao.AuthSessionKeyGet")
|
||||
defer span.End()
|
||||
|
||||
key := fmt.Sprintf(redismodel.KeyAuthSessionKey, userID)
|
||||
sessionKey, err := global.RedisEngine.Get(ctx, key).Result()
|
||||
if err != nil && err != redis.Nil {
|
||||
span.RecordError(err)
|
||||
}
|
||||
return sessionKey, err
|
||||
}
|
||||
Reference in New Issue
Block a user