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实现的,只不过做了二次封装。

二、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的长度越长越复杂越安全。

在正常情况下,要传入两个关键参数。第一个参数是 认证密钥(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。

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的一些参数,以满足应用程序的需求。

参数详细解释:

字段含义示例值
PathCookie的路径“/”
DomainCookie的域“your-domain.com”
MaxAge最大生存时间(秒)3600
Secure是否仅通过HTTPS传输true
HttpOnly是否禁止通过JavaScript访问Cookietrue
SameSiteSameSite属性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中读写数据,在高并发中并不适合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/352585.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jenkins+gitlab实现iOS自动打包的坎坷之路(本文包含CI\CD过程中的一些坑点以及一些理解及建议)

本文须知:本文成功案例是配置jekins所在服务器配置打包环境,并非在jenkins中配置打包环境。关于为何不采用在jenkins中配置打包环境将会在文中具体讲解。最后因为是基于jekins所在服务器配置的打包环境,按照本文所诉,实现ios自动打…

Java后端开发:学籍系统核心逻辑

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…

SQL语句创建一个简单的银行数据库

目录 一、银行业务E-R图 二、数据库模型图 转换关系模型后: 三、创建数据库 3.1 创建银行业务数据库 四、创建表 4.1 创建客户信息表 4.2 创建银行卡信息表 4.3 创建交易信息表 4.4 创建存款类型表 结果如下: ​编辑 五、插入适量数据 5.1…

【Python】字符串

🚩 WRITE IN FRONT 🚩 🔎 介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四" 🔎🏅 荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

android开发者模式@adb无线调试

文章目录 adb调试功能介绍有线调试无线调试 配置无线adb调试手机端开发者选项配置电脑端配置步骤初次使用进行配对链接设备小结 检查链接是否成功 技巧快速打开无线调试 refs adb调试 功能介绍 ADB(Android Debug Bridge)是一种强大的命令行工具&#…

Linux初始相关配置

前言 在学完了Linux的相关基础命令后,在正式使用Linux系统之前,我觉得配置一些东西是很有意义的。 文章目录 前言1.权限配置,普通用户无法sudo提权2.vim配置3.vim其他操作4.动静态库5.gcc/g6.程序翻译的过程7.make/makefile8.cmake/CMakeLis…

docker拉取镜像时指定其OS及CPU指令集类型

前言 之前在香橙派5上安装的时候碰到过一次指定镜像的OS及cpu指令集类型的问题,但是当时没有记录,现在用到 了又想不起来,干脆就自己记录一下。预防后面忘掉。docker报错截图 上次时在arm的cpu中运行x86镜像,这次时在x86中运行arm…

仰暮计划|“星星之火可以燎原,平凡人的一生同样值得称赞

传递助老之情,践行为老初心。为学习和发扬助老为老精神,我参与了康乐忆享实践队开展的以“仰暮计划”为主题的实践活动,在实践过程中了解老人的人生经历,传播尊老爱老思想。我与老人谭爷爷在谈论家常时,他拿出年轻时的…

Blender教程-物体的移动、旋转与缩放-04

一、新建一个立方体 ShiftA新建一个立方体用来演示。 二、物体的移动 xyz轴移动 点击下图图左侧的移动选项后,选中要移动的物体,会出现三个箭头的方向,这分别代表沿着x、y、z轴移动。xyz平面移动 这个小正方体代表沿着某一个面移动&#…

基于JAVA的陕西非物质文化遗产网站 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 设计目标2.2 研究内容2.3 研究方法与过程2.3.1 系统设计2.3.2 查阅文献2.3.3 网站分析2.3.4 网站设计2.3.5 网站实现2.3.6 系统测试与效果分析 三、系统展示四、核心代码4.1 查询民间文学4.2 查询传统音乐4.3 增改传统舞…

程序员的平均结婚年龄

关于程序员的平均结婚年龄,根据之前的信息: 一项对全球10000名在职程序员的调查数据显示,程序员第一次结婚的平均年龄是39.43周岁。而在中国的部分地区,如北京等地,程序员群体中普遍反映的结婚年龄是在30岁左右。 程序…

hive面试题

0. 思维导图 1. 简述Hive♥♥ 我理解的,hive就是一款构建数据仓库的工具,它可以就结构化的数据映射为一张表,并且可以通过SQL语句进行查询分析。本质上是将SQL转换为MapReduce或者spark来进行计算,数据是存储在hdfs上,…

带延迟的随机逼近方案(Stochastic approximation schemes):在网络和机器学习中的应用

1. 并行队列系统中的动态定价Dynamic pricing 1.1 系统的表述 一个含有并行队列的动态定价系统,该系统中对于每个队列有一个入口收费(entry charge) ,且系统运行的目标是保持队列长度接近于某个理想的配置。 这里是这个系统的几个关键假设:…

ASUS华硕无畏Pro15笔记本电脑(M6500QB,M6500QH)工厂模式原厂OEM预装Windows11.22H2系统 含Recovery恢复

原装出厂Windows11系统适用于华硕无畏15笔记本电脑型号:M6500QB和M6500QH 链接:https://pan.baidu.com/s/1AVGLN6-ILIRogOMj48Mk1w?pwdmi7d 提取码:mi7d 带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题专用壁纸、系统属性联机支持…

keil使用教程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据 总结 前言 例如:随着人工智能的不断发展,机器学习这门技术也越来越重…

Apipost数据库连接使用

Apipost提供了数据库连接功能,在接口调试时可以使用数据库获取入参或进行断言校验。目前的Apipost支持:Mysql、SQL Sever、Oracle、Clickhouse、达梦数据库、PostgreSQL、Redis、MongoDB 8种数据库的连接操作 新建数据库连接: 在「项目设置…

face_recognition和图像处理中left、top、right、bottom解释

face_recognition.face_locations 介绍 加载图像文件后直接调用face_recognition.face_locations(image),能定位所有图像中识别出的人脸位置信息,返回值是列表形式,列表中每一行是一张人脸的位置信息,包括[top, right, bottom, l…

[Python] 如何在Windows下安装图形可视化工具graphviz

什么是graphviz? Graphviz是一款开源的图形可视化工具,用于生成各种结构化数据的图形表示。它支持多种图形排列算法,可以将复杂的数据关系用图形的方式直观地展示出来。Graphviz广泛应用于软件工程、数据可视化、计算机网络以及其他领域的可视化分析中…

Java二分查找-图文

一、二分查找概念 二分查找也叫折半查找,是在一组有序(升序/降序)的数据中查找一个元素,它是一种效率较高的查找方。 二、二分查找原理 1.二分查找的数组必须是有序数值型数组。 2.将想要查找的目标元素与查找范围内的中间元素进行比较,如果…

python在线聊天室(带聊天保存)

python Socket在线聊天室(带聊天保存) 需求功能 1.聊天信息保存功能(服务端会把信息保存到一个txt里面) 2.使用pyqt5框架作为一个可视化界面 3.具备一个服务端和多个客户端的功能 4.具备离线加入黑名单(离线踢出) 5.具备在线加入黑名单(在线加入黑名单被踢出) 6.具备群聊功能…