您现在的位置是:首页 >技术交流 >go(gin框架)session底层使用redis实现(gorilla/sessions和gin-contrib/sessions)网站首页技术交流

go(gin框架)session底层使用redis实现(gorilla/sessions和gin-contrib/sessions)

瑶风 2023-05-14 19:27:12
简介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已经能用且满足需求了,就这样吧)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。