您现在的位置是:首页 >技术交流 >go(gin框架)session底层使用redis实现(gorilla/sessions和gin-contrib/sessions)网站首页技术交流
go(gin框架)session底层使用redis实现(gorilla/sessions和gin-contrib/sessions)
问题描述
最近在写一个基于gin框架的demo,需要实现简单的rbac,在网上找了一个有基础功能的基本框架,Go Gin Example,框架本身集成了基本功能:日志,mysql增删改查,路由,jwt认证等功能,在这个基础上,首先实现rbac。
考虑到redis做缓存比较好管理、文档丰富,且我和公司同事都有丰富的使用经验,且上一个项目就是使用的redis做session,因此尽量还是用redis。
在网上和chatGpt搜索,发现几乎没有立即可用的方案,都云里雾里的,感觉参考价值不高,因此自己看文档研究。
工具调研
目前市面上比较常用的go语言使用session(尤其是gin框架)工具包有:gin-contrib/sessions和gorilla/sessions.
gin-contrib/sessions使用
设置session
gin默认的工具就是gin-contrib/sessions,因此首先来看gin-contrib/sessions怎么使用
查阅文档,发现官方是有默认redis支持的,copy过来改一改。发现没有自动把session id给设置到cookie中,可能需要手动设置。
// SetUserSession 设置用户session
func SetUserSession(c *gin.Context, userRet *User) {
gob.Register(&User{})
session := sessions.Default(c)
session.Set("user-data", userRet)
session.Save()
sessionId := session.ID()
// 在这之前,需要先清除已有的cookie和session
userRet.LogOut(c)
middleware.SetCookie(c, "GOSESSID", "session_"+sessionId, 4*3600)
}
这里有个需要注意的点,获取sessionId需要在session.Save()执行之后,否则获取不到
middleware.SetCookie的作用是,设置一个名为GOSESSID
的cookie,值为"session_"+sessionId
。在各个请求中都能拿到这个cookie,进而去session中查询登录信息。
清除session
退出登录时,只需要获取到GOSESSID
的cookie内容,找到session的id(在redis中直接使用key存储),先清除session,再删除cookie
// LogOut 登出
func (u *User) LogOut(c *gin.Context) error {
redisKeyName, err := c.Cookie("GOSESSID")
if err != nil {
return err
}
gredis.Delete(redisKeyName)
middleware.ClearCookie(c, "GOSESSID", redisKeyName)
return nil
}
gorilla/sessions 使用
设置session
以下是设置缓存的代码(包含校验用户信息):
var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
// CheckUser 校验用户信息
func CheckUser(c *gin.Context, userName string, password string) error {
checkPassCompare, err := hashPassword(password)
if err != nil {
c.AbortWithStatusJSON(400, gin.H{"error": e.GetMsg(e.AuthFail)})
return err
}
equal, err := checkPassword(c, password, checkPassCompare)
if equal == false {
c.AbortWithStatusJSON(400, gin.H{"error": e.GetMsg(e.AuthFail)})
return err
}
userQuery := &User{
Username: userName,
Password: checkPassCompare,
}
userRet := &User{}
if err := db.Model(&User{}).Where(userQuery).Find(userRet).Error; err != nil {
return err
}
logging.Info(userRet.Username)
gob.Register(&User{})
session, _ := store.Get(c.Request, "GOSESSID")
session.Values["user-data"] = userRet
err = session.Save(c.Request, c.Writer)
if err != nil {
//c.AbortWithStatusJSON(e.ERROR, gin.H{"error": e.GetMsg(e.AuthFail)})
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return err
}
return nil
}
以上代码设置session,sessionId的key为GOSESSID,sessionId保存在cookie中(这句话不一定正确,只是我自己去实现后得到的结果,原本我是想copy下chatGpt的代码,结果chatGpt一直胡说八道,让我绕了很久的弯路…)。
清除session
清除session就是获取session的值,设置为nil即可,但是要注意,cookie里会记录sessionId,也需要清除:
// ClearSessions 清除session
func ClearSessions(c *gin.Context, store *sessions.CookieStore, sessionName string, cookieName string) {
// 获取一个新的 session 存储器
// 获取一个 session
session, err := store.Get(c.Request, sessionName)
if err != nil {
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return
}
session.Values[sessionName] = nil
// 清除所有的 session 数据
session.Options.MaxAge = -1
// 保存 session 更改
err = session.Save(c.Request, c.Writer)
if err != nil {
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return
}
ClearCookie(c, cookieName)
// 返回成功信息
logging.Info("All sessions cleared")
}
// ClearCookie 清除cookie
func ClearCookie(c *gin.Context, cookieName string) {
c.SetCookie(cookieName, "", -1, "/", "", false, true)
logging.Info("Cookie cleared")
}
以上代码能实现一个非常基础简单的session使用。
gorilla/sessions使用redis
chatGpt多次询问,依然推荐使用github.com/gorilla/sessions/redisstore
包,然而这个包早就不维护了,使用了新版gorilla/sessions包,无法下载,会报:go: module github.com/gorilla/sessions@upgrade found (v1.2.1), but does not contain package github.com/gorilla/sessions/redisstore
,实际上,chatGpt只有21年9月份以前的数据,这是过时的。要么就是建议使用sessions.NewRedisStore
,实际上也已经没有NewRedisStore
方法了,因此先去阅读最新的gorilla/sessions包文档。
gorilla/sessions的readme中提及了两个redis相关的库:boj/redistore和…(抱歉,写一半不想写了,因为我发现这两个库上次更新时间都很久远,而且蛮多issue都没有关闭,因此不想去踩坑了,反正gin-contrib/sessions已经能用且满足需求了,就这样吧)