添加会话过期时间的环境变量配置;撤销令牌接口权限改为验证用户令牌

This commit is contained in:
2025-04-30 16:39:46 +08:00
parent fa356431ee
commit 1976baa164
4 changed files with 64 additions and 67 deletions

View File

@@ -1,24 +1,23 @@
## todo
- 撤销令牌需要改成用户权限,只有本人可以撤销
- 移动端适配
- 扩展 device 权限验证方式,提供一种方法区分内部和外部服务
- 检查数据库枚举字段0 值只作为空值使用
- 更新数据库填充
- 微信支付
- 错误处理类型转换失败问题
- 用对称加密处理密钥
- 检查数据库枚举字段0 值只作为空值使用
- 移动端适配
- channel 接口
- 重新梳理逻辑流程,简化循环
- 端口分配时加锁
- 用对称加密处理密钥
- 环境变量配置默认会话配置
- 微信支付
- 支付回调处理
- 页面 账户总览
- 保存 session 到数据库
- 中间件 Limiter
- 中间件 Compress
- 页面 账户总览
- 页面 提取记录
- 页面 使用记录
### 下阶段
- 支付回调处理
- 保存 session 到数据库
- 扩展 device 权限验证方式,提供一种方法区分内部和外部服务
- 废弃 password 授权模式,迁移到 authorization code 授权模式
- oauth token 验证授权范围
- 实现白银节点的 warp 服务,用来去重与端口分配,保证测试与生产环境不会产生端口竞争
@@ -27,6 +26,7 @@
- debug白银节点提供一些工具接口方便快速操作
- 批量下线端口
- 统一使用 validator 进行参数验证
- 格式化控制台输出
### 长期

30
pkg/env/env.go vendored
View File

@@ -24,6 +24,35 @@ func loadApp() {
// endregion
// region auth
var (
SessionAccessExpire = 60 * 60 * 2 // 2小时
SessionRefreshExpire = 60 * 60 * 24 * 7 // 7天
)
func loadAuth() {
_SessionAccessExpire := os.Getenv("SESSION_ACCESS_EXPIRE")
if _SessionAccessExpire != "" {
value, err := strconv.Atoi(_SessionAccessExpire)
if err != nil {
panic("环境变量 SESSION_ACCESS_EXPIRE 的值不是数字")
}
SessionAccessExpire = value
}
_SessionRefreshExpire := os.Getenv("SESSION_REFRESH_EXPIRE")
if _SessionRefreshExpire != "" {
value, err := strconv.Atoi(_SessionRefreshExpire)
if err != nil {
panic("环境变量 SESSION_REFRESH_EXPIRE 的值不是数字")
}
SessionRefreshExpire = value
}
}
// endregion
// region db
var (
@@ -359,6 +388,7 @@ func Init() {
}
loadApp()
loadAuth()
loadDb()
loadRedis()
loadLog()

View File

@@ -268,7 +268,7 @@ type RevokeReq struct {
}
func Revoke(c *fiber.Ctx) error {
_, err := auth.Protect(c, []s.PayloadType{s.PayloadClientConfidential}, []string{})
_, err := auth.Protect(c, []s.PayloadType{s.PayloadUser}, []string{})
if err != nil {
// 用户未登录
return nil

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"platform/pkg/env"
"platform/pkg/rds"
"time"
@@ -20,9 +21,9 @@ type SessionServiceInter interface {
// Find 通过访问令牌获取会话信息
Find(ctx context.Context, token string) (*AuthContext, error)
// Create 创建一个新的会话
Create(ctx context.Context, auth AuthContext, config ...SessionConfig) (*TokenDetails, error)
Create(ctx context.Context, auth AuthContext) (*TokenDetails, error)
// Refresh 刷新一个会话
Refresh(ctx context.Context, refreshToken string, config ...SessionConfig) (*TokenDetails, error)
Refresh(ctx context.Context, refreshToken string) (*TokenDetails, error)
// Remove 删除会话
Remove(ctx context.Context, accessToken, refreshToken string) error
}
@@ -61,12 +62,8 @@ func (s *sessionService) Find(ctx context.Context, token string) (*AuthContext,
}
// Create 创建一个新的会话
func (s *sessionService) Create(ctx context.Context, auth AuthContext, config ...SessionConfig) (*TokenDetails, error) {
// 解析可选配置
cfg := DefaultSessionConfig
if len(config) > 0 {
cfg = mergeConfig(DefaultSessionConfig, config[0])
}
func (s *sessionService) Create(ctx context.Context, auth AuthContext) (*TokenDetails, error) {
var now = time.Now()
// 生成令牌组
accessToken := genToken()
@@ -88,9 +85,12 @@ func (s *sessionService) Create(ctx context.Context, auth AuthContext, config ..
}
// 事务保存数据到 Redis
var accessExpire = time.Duration(env.SessionAccessExpire) * time.Second
var refreshExpire = time.Duration(env.SessionRefreshExpire) * time.Second
pipe := rds.Client.TxPipeline()
pipe.Set(ctx, accessKey(accessToken), authData, cfg.AccessTokenDuration)
pipe.Set(ctx, refreshKey(refreshToken), refreshData, cfg.RefreshTokenDuration)
pipe.Set(ctx, accessKey(accessToken), authData, accessExpire)
pipe.Set(ctx, refreshKey(refreshToken), refreshData, refreshExpire)
_, err = pipe.Exec(ctx)
if err != nil {
return nil, err
@@ -98,20 +98,16 @@ func (s *sessionService) Create(ctx context.Context, auth AuthContext, config ..
return &TokenDetails{
AccessToken: accessToken,
AccessTokenExpires: time.Now().Add(cfg.AccessTokenDuration),
AccessTokenExpires: now.Add(accessExpire),
RefreshToken: refreshToken,
RefreshTokenExpires: time.Now().Add(cfg.RefreshTokenDuration),
RefreshTokenExpires: now.Add(refreshExpire),
Auth: auth,
}, nil
}
// Refresh 刷新一个会话
func (s *sessionService) Refresh(ctx context.Context, refreshToken string, config ...SessionConfig) (*TokenDetails, error) {
// 解析可选配置
cfg := DefaultSessionConfig
if len(config) > 0 {
cfg = mergeConfig(DefaultSessionConfig, config[0])
}
func (s *sessionService) Refresh(ctx context.Context, refreshToken string) (*TokenDetails, error) {
var now = time.Now()
rKey := refreshKey(refreshToken)
var tokenDetails *TokenDetails
@@ -153,8 +149,11 @@ func (s *sessionService) Refresh(ctx context.Context, refreshToken string, confi
pipeline := tx.Pipeline()
// 保存新的令牌
pipeline.Set(ctx, accessKey(newAccessToken), authData, cfg.AccessTokenDuration)
pipeline.Set(ctx, refreshKey(newRefreshToken), newRefreshData, cfg.RefreshTokenDuration)
var accessExpire = time.Duration(env.SessionAccessExpire) * time.Second
var refreshExpire = time.Duration(env.SessionRefreshExpire) * time.Second
pipeline.Set(ctx, accessKey(newAccessToken), authData, accessExpire)
pipeline.Set(ctx, refreshKey(newRefreshToken), newRefreshData, refreshExpire)
// 删除旧的令牌
pipeline.Del(ctx, accessKey(refreshData.AccessToken))
@@ -168,8 +167,8 @@ func (s *sessionService) Refresh(ctx context.Context, refreshToken string, confi
tokenDetails = &TokenDetails{
AccessToken: newAccessToken,
RefreshToken: newRefreshToken,
AccessTokenExpires: time.Now().Add(cfg.AccessTokenDuration),
RefreshTokenExpires: time.Now().Add(cfg.RefreshTokenDuration),
AccessTokenExpires: now.Add(accessExpire),
RefreshTokenExpires: now.Add(refreshExpire),
Auth: refreshData.AuthContext,
}
return nil
@@ -204,38 +203,6 @@ func refreshKey(token string) string {
// endregion
// region SessionConfig
// SessionConfig 定义会话管理的配置选项
type SessionConfig struct {
// 令牌配置
AccessTokenDuration time.Duration
RefreshTokenDuration time.Duration
}
// DefaultSessionConfig 默认会话配置
var DefaultSessionConfig = SessionConfig{
AccessTokenDuration: 2 * time.Hour,
RefreshTokenDuration: 7 * 24 * time.Hour,
}
// 合并配置,保留非零值
func mergeConfig(defaultCfg SessionConfig, customCfg SessionConfig) SessionConfig {
result := defaultCfg
if customCfg.AccessTokenDuration != 0 {
result.AccessTokenDuration = customCfg.AccessTokenDuration
}
if customCfg.RefreshTokenDuration != 0 {
result.RefreshTokenDuration = customCfg.RefreshTokenDuration
}
return result
}
// endregion
// region AuthContext
// AuthContext 定义认证信息