- 导航项重新排序:首页、投稿、信封图标、头像下拉菜单 - 铃铛图标替换为信封图标 - 用户名/设置/退出移入头像 hover 下拉菜单 - 设置改名为个人中心,退出改名为退出登录 - 头像点击跳转 /space,hover 展开下拉菜单 - 无头像时显示用户名首字彩色圆形占位 - Avatar 数据链路打通:Session→Middleware→BuildPageData→模板 - FindByIDForAuth 查询增加 avatar 列 - 新增 substr 模板函数
43 lines
1.1 KiB
Go
43 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 // 用户名
|
||
Avatar string // 头像 URL
|
||
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
|
||
}
|