Gin 应用多实例部署session问题、session参数与刷新

这篇具有很好参考价值的文章主要介绍了Gin 应用多实例部署session问题、session参数与刷新。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • 一、Gin Session 存储的实现方案
  • 二、memstore:基于内存的实现
    • 2.1 基本使用
    • 2.2 关键参数
  • 三、使用redis:多实例部署
    • 3.1 使用redis优势
    • 3.2 基本使用
  • 四、信息安全的三个核心概念
  • 五、Gin Session 参数
    • 5.1 参数介绍
  • 六、Session 自动刷新

一、Gin Session 存储的实现方案

  • cookie:基于cookie的实现,不安全,一般不会使用。
  • gorm:基于 GORM 的实现
  • memcached:基于 Memcached 的实现
  • memstore:基于内存的实现,一般单实例部署用的比较多,或者本地测试。
  • mongo:基于 MongoDB 的实现
  • postgres:基于 PostgreSQL 的实现
  • redis:基于 Redis 的实现,多实例部署,应该无脑选 redis 实现。
  • tester:用于测试的实现

其实Gin 中的session 是通过github.com/gorilla/sessions实现的,只不过做了二次封装。

Gin 应用多实例部署session问题、session参数与刷新

二、memstore:基于内存的实现

2.1 基本使用

memstoregithub.com/gin-contrib/sessions库提供的一个基于内存的Session存储后端。它将Session数据存储在应用程序的内存中,适用于小型应用或用于开发和测试目的。以下是一个使用memstore的简单示例:

  1. 安装gin-contrib/sessions库:

    go get -u github.com/gin-contrib/sessions
    
  2. 使用memstore存储Session:

    package main
    
    import (
    	"github.com/gin-contrib/sessions"
    	"github.com/gin-contrib/sessions/memstore"
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 初始化Gin引擎
    	router := gin.Default()
        // 用内存存储 session
    	// 这是基于内存的实现,第一个参数是 authentication key,最好是 32 或者64 位
    	//第二个参数是 encryption key
    	store := memstore.NewStore([]byte("moyn8y9abnd7q4zkq2m73yw8tu9j5ixm"),[]byte("o6idlo2cb9f9pb6h46fimllw481ldebi"))
    	router.Use(sessions.Sessions("mysession", store))
    
    	// 路由示例
    	router.GET("/set", func(c *gin.Context) {
    		// 设置Session
    		session := sessions.Default(c)
    		session.Set("key", "value")
    		session.Save()
    
    		c.JSON(200, gin.H{"message": "Session set"})
    	})
    
    	router.GET("/get", func(c *gin.Context) {
    		// 获取Session
    		session := sessions.Default(c)
    		value := session.Get("key")
    
    		c.JSON(200, gin.H{"key": value})
    	})
    
    	// 启动服务
    	router.Run(":8080")
    }
    
    

    在上述示例中,我们使用了memstore.NewStore创建一个基于内存的Session存储后端。记得在实际应用中,根据实际需求选择适当的Session存储后端,例如,在生产环境中可能更常见的是使用像Redis这样的持久化存储。

    请注意,memstore是基于内存的,如果应用程序重新启动,所有存储在内存中的Session数据将被清除。因此,它最适用于短期的Session需求,而不适用于长期的数据存储。在实际生产环境中,需要根据应用程序的需求选择合适的Session存储后端。

2.2 关键参数

我们通过NewStore入口进入,可以看到,官方要求传入鉴权和加密的Key对于Key的长度越长越复杂越安全。

Gin 应用多实例部署session问题、session参数与刷新

在正常情况下,要传入两个关键参数。第一个参数是 认证密钥(authentication key),最好是 32 或者 64 位。第二个参数是 加密密钥(encryption key)。

// 用内存存储 session
// 这是基于内存的实现,第一个参数是 authentication key,最好是 32 或者64 位
//第二个参数是 encryption key
store := memstore.NewStore([]byte("moyn8y9abnd7q4zkq2m73yw8tu9j5ixm"),[]byte("o6idlo2cb9f9pb6h46fimllw481ldebi"))
// cookie 的名字叫做sessions
ser.Use(sessions.Sessions("sessions", store))// 登录校验
ser.Use(middleware.NewLoginMiddlewareBuilder().Build())

三、使用redis:多实例部署

3.1 使用redis优势

在分布式环境下(包括单例应用多实例部署),都需要确保 Session 在每一个实例上都可以访问到,而单节点只能访问当前环境的Session。

Gin 应用多实例部署session问题、session参数与刷新

3.2 基本使用

在使用Redis作为Session存储时,你需要使用Gin框架的github.com/gin-contrib/sessions中间件,并选择一个支持Redis的Session存储后端,比如github.com/gin-contrib/sessions/redis

以下是一个基本的使用示例:

  1. 安装依赖:

    go get -u github.com/gin-contrib/sessions
    go get -u github.com/gin-contrib/sessions/redis
    
  2. 使用Redis存储Session:

    package main
    
    import (
    	"github.com/gin-contrib/sessions"
    	"github.com/gin-contrib/sessions/redis"
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 初始化Gin引擎
    	router := gin.Default()
    
    	// 使用Redis存储Session
    	store, err := redis.NewStore(
    		16,               // 最大空闲链接数量,过大会浪费,过小将来会触发性能瓶颈
    		"tcp",            // 指定与Redis服务器通信的网络类型,通常为"tcp"
    		"localhost:6379", // Redis服务器的地址,格式为"host:port"
    		"",               // Redis服务器的密码,如果没有密码可以为空字符串
    		[]byte("95osj3fUD7fo0mlYdDbncXz4VD2igvf0"), // authentication key
    		[]byte("0Pf2r0wZBpXVXlQNdpwCXN4ncnlnZSc3"), // encryption key
    	)
    
    	if err != nil {
    		panic(err)
    	}
    
    	// 设置Session中间件
    	router.Use(sessions.Sessions("mysession", store))
    
    	// 路由示例
    	router.GET("/set", func(c *gin.Context) {
    		// 设置Session
    		session := sessions.Default(c)
    		session.Set("key", "value")
    		session.Save()
    
    		c.JSON(200, gin.H{"message": "Session set"})
    	})
    
    	router.GET("/get", func(c *gin.Context) {
    		// 获取Session
    		session := sessions.Default(c)
    		value := session.Get("key")
    
    		c.JSON(200, gin.H{"key": value})
    	})
    
    	// 启动服务
    	router.Run(":8080")
    }
    
    

    在上述示例中,我们使用了redis.NewStore创建一个基于Redis的Session存储后端。你需要提供Redis服务器的地址、密码和密钥等信息。

四、信息安全的三个核心概念

  1. 身份认证(Authentication): 身份认证是确认用户或系统的身份是否合法的过程。在身份认证中,用户提供的身份信息(例如用户名和密码、生物特征等)被验证以确定其是否有权访问系统或资源。常见的身份认证方式包括用户名密码认证、多因素认证(例如使用手机验证码或硬件令牌)、生物特征认证等。
  2. 数据加密(Encryption): 数据加密是通过使用算法将信息转化为密文,以确保只有具备正确密钥的人或系统能够解密和访问原始信息。数据加密对于保护敏感信息、防止数据泄露和维护隐私非常重要。常见的加密算法包括对称加密(同一个密钥用于加密和解密)和非对称加密(使用一对密钥,一个用于加密,另一个用于解密)。
  3. 权限控制(Authorization): 权限控制是确保用户或系统在身份认证成功后只能访问其被授权的资源和执行其被授权的操作的过程。这包括定义用户或系统的角色、分配权限、限制访问范围等。权限控制有助于防止未经授权的访问和确保系统的安全性。

五、Gin Session 参数

5.1 参数介绍

在Gin框架中,Session的参数可以通过Options方法来传入OptionOptions方法用于配置Session的一些参数,以满足应用程序的需求。

Gin 应用多实例部署session问题、session参数与刷新

参数详细解释:

字段 含义 示例值
Path Cookie的路径 "/"
Domain Cookie的域 "your-domain.com"
MaxAge 最大生存时间(秒) 3600
Secure 是否仅通过HTTPS传输 true
HttpOnly 是否禁止通过JavaScript访问Cookie true
SameSite SameSite属性 http.SameSiteLaxMode

举个例子:

package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	// 初始化Gin引擎
	router := gin.Default()

	// 配置Session
	store := sessions.NewCookieStore([]byte("your-secret-key"))
	store.Options(sessions.Options{
		Path:     "/",
		Domain:   "your-domain.com",
		MaxAge:   3600, // 设置为3600秒,即1小时
		Secure:   true, // 仅通过HTTPS传输Cookie
		HttpOnly: true, // 禁止通过JavaScript访问Cookie
		SameSite: http.SameSiteLaxMode, // SameSite属性,限制在顶级导航时发送
	})
	router.Use(sessions.Sessions("mysession", store))

	// 路由示例
	router.GET("/set", func(c *gin.Context) {
		// 设置Session
		session := sessions.Default(c)
		session.Set("key", "value")
		session.Save()

		c.JSON(200, gin.H{"message": "Session set"})
	})

	router.GET("/get", func(c *gin.Context) {
		// 获取Session
		session := sessions.Default(c)
		value := session.Get("key")

		c.JSON(200, gin.H{"key": value})
	})

	// 启动服务
	router.Run(":8080")
}

六、Session 自动刷新

实现方式,在中间件中设置一个更新时间:

// LoginMiddlewareBuilder 结构体的 Build 方法,用于构建 Gin 中间件
func (l *LoginMiddlewareBuilder) Build() gin.HandlerFunc {
	// 使用 gob 注册 time.Now(),以便在 Session 中存储 time.Time 类型
	gob.Register(time.Now())

	// 返回一个 Gin 中间件函数
	return func(ctx *gin.Context) {
		// 检查当前请求路径是否为不需要登录校验的路径
		if ctx.Request.URL.Path == "/users/login" ||
			ctx.Request.URL.Path == "/users/signup" {
			// 如果是不需要登录校验的路径,直接返回,不进行后续的登录检查
			return
		}

		// 获取默认的 Session
		sess := sessions.Default(ctx)

		// 获取 Session 中存储的 userId
		id := sess.Get("userId")

		// 如果 userId 不存在,说明用户未登录,返回未授权状态码
		if id == nil {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		// 获取 Session 中的 updateTime
		updateTime := sess.Get("update_time")

		// 设置 Session 的 userId,并配置 Session 的过期时间为 60 秒
		sess.Set("userId", id)
		sess.Options(sessions.Options{
			MaxAge: 60,
		})

		now := time.Now()

		// 如果 updateTime 为空,说明是第一次登录,设置 update_time 并保存 Session
		if updateTime == nil {
			sess.Set("update_time", now)
			if err := sess.Save(); err != nil {
				panic(err)
			}
		}

		// 如果 updateTime 不为空,说明已经登录过,检查是否超过 10 秒,超过则刷新 update_time 并保存 Session
		updateTimeVal, _ := updateTime.(time.Time)
		if now.Sub(updateTimeVal) > time.Second*10 {
			sess.Set("update_time", now)
			if err := sess.Save(); err != nil {
				panic(err)
			}
		}
	}
}

缺点:由于这种方式每次都要从Redis中读写数据,在高并发中并不适合。文章来源地址https://www.toymoban.com/news/detail-824990.html

到了这里,关于Gin 应用多实例部署session问题、session参数与刷新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Gin 框架之Cookie与Session

    我们知道 HTTP协议无连接 的, 也就是不保存用户的状态信息。 早期(十几年前)的网页是静态的, 数据都是写死的, 人们访问网页只是用来查看新闻的, 没有保存用户状态的需求。 而往后出现了像论坛、博客、网购这一类需要保存用户信息的网站, 如果网站不保存用户的状态信息

    2024年01月20日
    浏览(26)
  • 解决Vue3+Vite3 打包部署到nginx后配置非根目录刷新页面报错空白

    报错内容 解决方法 router文件 vite.config.ts nginx.conf 配置中路径apps是我自建的存放前端页面的文件夹 起关键作用的是 try_files $uri $uri/ /demo/index.html ,当然上面项目文件夹demo也需保持一致 alias 后面的路径是Vue项目打包后dist静态文件服务器存放路径,一般在nginx下面建一个文件夹

    2024年02月11日
    浏览(32)
  • 【Visual Studio 2022创建ASP.NET Web应用程序(.NET Framework)发布并部署到局域网 及“常见权限问题和不列出目录问题解决”】

    然后给项目命名并选择文件保存位置 用一个空项目进行举例 创建完成如下 点击更多模板选择Web窗体 创建成功如下 .aspx页面编写前端代码,.aspx.cs页面编写后端代码 通过插入表格和拉取控件快速完成 然后给Button按钮设置一个点击事件,双击按钮后会跳到.aspx.cs页面,完善下面

    2024年02月07日
    浏览(65)
  • gin会话控制篇 - Cookie和Session

    HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出 Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思 Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求

    2024年01月21日
    浏览(29)
  • 了解 Gin 中的 cookie、session 以及 cache 使用

    了解 Gin 中的 cookie、session 以及 cache 使用,并通过具体例子,掌握它们在不同场景下的应用。 Cookie: Cookie 是存储在用户浏览器中的小型文本文件,通常用于存储用户身份验证信息、个性化设置等。在使用 Gin 时,可以很方便地读取和设置 Cookie。 具体例子: 1.1 设置 Cookie:

    2024年02月07日
    浏览(30)
  • ES近实时刷新与refresh_interval参数设置相关问题

    ES中的查询是近实时的,也就是说当数据添加到索引后并不能马上被查询到,等到索引刷新后才会被查询到,索引刷新相关字段为refresh_interval,默认为1s刷新一次。 为何说ES的查询是近实时的呢?首先先了解下ES写入数据的过程: ES写入数据是先把数据写进 Luence 的**\\\"memory bu

    2024年02月06日
    浏览(44)
  • 若依前端,菜单栏切换时刷新问题[页面菜单切换时,页面总是重新刷新,导致页面输入的查询参数重载清空]...

    前端页面菜单切换时,页面总是重新刷新,导致页面输入的查询参数重载清空 这样切换时,页面就刷新了,解决方法在这里 1,页面代码,这里指定name name: \\\"Item\\\", 注意 name的首字母必须大写 2,页面代码,这里指定id id=\\\"item\\\" 注意,id的首字母必须小写 3,页面配置,这里的路由

    2024年02月12日
    浏览(44)
  • 华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu

    华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu 介绍华为云云耀云服务器 华为云云耀云服务器 (目前已经全新升级为 华为云云耀云服务器L实例) 华为云云耀云服务器是什么 华为云云耀云服务器和上一代

    2024年02月07日
    浏览(61)
  • 前端部署nginx刷新后404,解决Nginx刷新页面后404的问题

    使用Nginx部署后,登录页面刷新一下就出来404,如下图: 刷新以后 ,页面变成404 Not Found 查看了一下nginx配置,出现问题的配置是这样的: 修改后的配置是这样的 添加了 try_files $uri $uri/ /index.html, 然后重启一下nginx问题就解决了。 解释: try_files 表示检查文件是否存在,返回

    2024年02月13日
    浏览(36)
  • FFmpeg最常用命令参数详解及应用实例

    FFMPEG堪称自由软件中最完备的一套多媒体支持库,它几乎实现了所有当下常见的数据封装格式、多媒体传输协议以及音视频编解码器,提供了录制、转换以及流化音视频的完整解决方案。 ffmpeg -i [输入文件名] [参数选项] -f [格式] [输出文件] ffmpeg [[ options ][ -i input_file ]]... {[

    2024年01月24日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包