- Session 结构体新增 IP、UserAgent、Remark 字段,登录/注册时记录设备信息 - Store 接口新增 ListByUID、DeleteByUIDExclude 方法,MemoryStore 完整实现 - SessionManager 新增 ListByUID、DestroyOtherByUID、UpdateRemark 方法 - 新增 UA 轻量解析器(session/ua.go),提取浏览器/OS/设备类型 - 新增 settings_api_sessions.go,提供列表/踢出/一键踢出/备注 4 个 API - 控制器层声明 sessionManager 最小接口(ISP),SettingsController 注入依赖 - Auth 中间件注入 sid 到 gin context,支持识别当前会话 - 设置页左侧导航增加登录管理入口,tab 白名单新增 sessions - 前端实现设备列表展示(浏览器/OS/设备图标/IP/时间)、当前设备标识、备注输入、踢出按钮、一键踢出 - settings.css 新增会话管理全套样式及响应式适配
42 lines
1.1 KiB
Go
42 lines
1.1 KiB
Go
package session
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"encoding/hex"
|
||
"time"
|
||
)
|
||
|
||
// Session 服务端会话,替代 JWT 无状态令牌
|
||
type Session struct {
|
||
ID string // 会话唯一标识(64 位 hex)
|
||
UserID uint // 用户 ID
|
||
Email string // 邮箱
|
||
Username string // 用户名
|
||
Role string // 角色
|
||
RememberMe bool // 是否持久化(决定 cookie maxAge)
|
||
IP string // 登录 IP
|
||
UserAgent string // 登录设备 User-Agent
|
||
Remark string // 用户备注(如"我的笔记本")
|
||
CreatedAt time.Time // 创建时间
|
||
LastAccess time.Time // 最后访问时间(滑动窗口)
|
||
}
|
||
|
||
// IsExpired 检查会话是否已过期
|
||
func (s *Session) IsExpired(idleTimeout time.Duration) bool {
|
||
return time.Since(s.LastAccess) > idleTimeout
|
||
}
|
||
|
||
// Touch 更新最后访问时间(续期)
|
||
func (s *Session) Touch() {
|
||
s.LastAccess = time.Now()
|
||
}
|
||
|
||
// NewID 生成 32 字节随机 hex 字符串作为会话 ID
|
||
func NewID() (string, error) {
|
||
b := make([]byte, 32)
|
||
if _, err := rand.Read(b); err != nil {
|
||
return "", err
|
||
}
|
||
return hex.EncodeToString(b), nil
|
||
}
|