Session管理 原创
上一节我们实现了用户登录模块,当用户成功登录后,会给用户生成一个 token,后续的请求只要携带上 token 就可以操作 API 了。
只要 token 未过期,用户可以一直使用这个 token,就算进行了用户退出的操作,也没有特别好的办法直接修改 token 的过期时间。
为此,这里对登录进行改造:用户登录->生成 Token->存储 Session。登录过后的 API 都需要通过 Session 进行校验,退出登录则把后端保存的 session 删除掉。
通常情况下,我们会将 session 保存到缓存数据库中,比如 redis,我们这里也使用 Redis 来存储。
添加配置文件
(1)在 config.yaml 中添加以下配置信息
yaml
Cache:
Type: redis
Address: 127.0.0.1:6379
Password: ""
MaxConnect: 10
Network: tcp
Secret: "hawkeye"
(2)在 pkg/section.go 中增加缓存相关结构体
go
// CacheSettingS 缓存配置
type CacheSettingS struct {
Type string
Address string
Password string
MaxConnect int
Network string
Secret string
}
(3)在 initialize/setting.go 中增加读取缓存配置
go
package initialize
import (
"github.com/joker-bai/hawkeye/global"
"github.com/joker-bai/hawkeye/pkg/setting"
)
// SetupSetting 初始化配置
func SetupSetting() error {
s, err := setting.NewSetting()
if err != nil {
return err
}
......
// 加载缓存配置
if err := s.ReadSection("Cache", &global.CacheSetting); err != nil {
return err
}
return nil
}
在 global/setting.go 中增加 CacheSetting 变量。
go
package global
import "github.com/joker-bai/hawkeye/pkg/setting"
var (
ServerSetting *setting.ServerSettingS
DatabaseSetting *setting.DatabaseSettingS
AppSetting *setting.AppSettingS
CacheSetting *setting.CacheSettingS
)
初始化 Session
(1)在 initialize/session.go 中增加以下代码用于初始化 Session 存储。
go
package initialize
import (
"github.com/gin-contrib/sessions/redis"
"github.com/joker-bai/hawkeye/global"
)
func SetupSession() error {
var err error
global.SessionStore, err = redis.NewStore(
global.CacheSetting.MaxConnect,
global.CacheSetting.Network,
global.CacheSetting.Address,
global.CacheSetting.Password,
[]byte(global.CacheSetting.Secret),
)
if err != nil {
return err
}
return nil
}
在 global/session.go 中增加以下变量。
go
package global
import "github.com/gin-contrib/sessions"
var (
SessionStore sessions.Store
)
(2)在 main.go 中增加初始化代码
go
func init() {
......
// 初始化Session
if err := initialize.SetupSession(); err != nil {
log.Fatalf("Failed to init session store, error: %s", err)
}
}
修改登录操作
在internal\app\controllers\api\v1\auth.go
中增加存入 session 的操作,如下:
go
package v1
import (
"encoding/json"
"time"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/joker-bai/hawkeye/global"
"github.com/joker-bai/hawkeye/internal/app/requests"
"github.com/joker-bai/hawkeye/internal/app/services"
"github.com/joker-bai/hawkeye/pkg/app"
"github.com/joker-bai/hawkeye/pkg/errorcode"
"github.com/joker-bai/hawkeye/pkg/jwt"
"github.com/joker-bai/hawkeye/pkg/tools"
"github.com/spf13/cast"
"go.uber.org/zap"
)
type AuthController struct{}
// Create godoc
// @Summary 用户登录
// @Description 用户登录
// @Tags 认证管理
// @Produce json
// @Param body body requests.AuthLoginRequest true "body"
// @Success 200 {object} string "成功"
// @Failure 400 {object} errorcode.Error "请求错误"
// @Failure 500 {object} errorcode.Error "内部错误"
// @Router /api/v1/auth/login [post]
func (u *AuthController) Login(ctx *gin.Context) {
......
// 存入session
sessionInfo := requests.LoginSessionInfo{
Username: param.Username,
Token: token,
LoginTime: time.Now(),
}
sessionBty, err := json.Marshal(sessionInfo)
if err != nil {
return
}
session := sessions.Default(ctx)
session.Set(tools.EncodeMD5(user.Username), string(sessionBty))
_ = session.Save()
response.ToResponse(gin.H{
"data": user,
"token": token,
})
}
然后在internal\app\requests\session.go
中增加LoginSessionInfo
结构体。
go
package requests
import "time"
type LoginSessionInfo struct {
Username string `json:"username"`
Token string `json:"token"`
LoginTime time.Time `json:"login_time"`
}
在pkg\tools\md5.go
中增加 MD5 加密方法。
go
package tools
import (
"crypto/md5"
"encoding/hex"
)
// EncodeMD5 MD5加密
func EncodeMD5(value string) string {
m := md5.New()
m.Write([]byte(value))
return hex.EncodeToString(m.Sum(nil))
}