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

参数详细解释:

字段 含义 示例值
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中读写数据,在高并发中并不适合。

Gin 应用多实例部署session问题、session参数与刷新的更多相关文章

  1. 使用Tomcat-redis-session-manager来实现Tomcat集群部署中的Session共享

    一.工作中因为要使用到Tomcat集群部署,此时就涉及到了Session共享问题,主要有三种解决方案: 1.使用数据库来存储Session 2.使用Cookie来存储Session 3.使用Redis ...

  2. 使用Tomcat+Redis来实现集群部署中的Session共享问题

    一.工作中因为要使用到Tomcat集群部署,此时就涉及到了Session共享问题,主要有三种解决方案: 1.使用数据库来存储Session 2.使用Cookie来存储Session 3.使用Redis ...

  3. HAProxy负载均衡原理及企业级实例部署haproxy集群

    一 HAProxy简介   HAProxy是一种高效.可靠.免费的高可用及负载均衡解决方案,非常适合于高负载站点的七层数据请求.客户端通过HAProxy代理服务器获得站点页面,而代理服务器收到客户请求 ...

  4. Tomcat 单(多)实例部署使用

    一.前言 (一).概述 Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控 ...

  5. 19.Tomcat多实例部署及负载均衡、动静分离

    Tomcat多实例部署及负载均衡.动静分离 目录 Tomcat多实例部署及负载均衡.动静分离 Tomcat多实例部署 安装jdk 设置jdk环境变量 安装tomcat 配置 tomcat 环境变量 修 ...

  6. Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  7. 什么是cookie?什么是session?session和cookie有什么区别?

    在技术面试中,经常被问到“说说Cookie和Session的区别”,大家都知道,Session是存储在服务器端的,Cookie是存储在客户端的,然而如果让你更详细地说明,你能说出几点?今天个推君就和大 ...

  8. Spring Session解决Session共享

    1. 分布式Session共享   在分布式集群部署环境下,使用Session存储用户信息,往往出现Session不能共享问题.   例如:服务集群部署后,分为服务A和服务B,当用户登录时负载到服务A ...

  9. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  10. PHP自带Session隐患(session文件独占锁引起阻塞)

    PHP自带Session隐患(session文件独占锁引起阻塞) PHP默认的会话处理器是session.save_handler = files(即文件).如果同一个客户端同时并发发送多个请求(如a ...

随机推荐

  1. 提速 10 倍!深度解读字节跳动新型云原生 Spark History Server

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 前不久,在 6月29日 Databricks 举办的 Data + AI Summit 上,火山引擎向大家首次介绍 ...

  2. 火山引擎 DataTester 背后,抖音的名字原来是 AB 测试来的

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 抖音的名字是怎么来的? 在字节跳动火山引擎技术开放日上,字节跳动副总裁杨震原曾透露过"抖音"名 ...

  3. Jenkins Pipeline 流水线 - Parameters 参数化构建

    可以通过参数的方式,指定构建的版本 有两种方式 界面添加 Pipeline Script 脚本配置 (需要Build 一次,然后生效,不知道有没有其它办法) General 界面添加 Pipeline ...

  4. 引用 AspNetCoreRateLimit => StatusCode cannot be set because the response has already started.

    app.UseIpRateLimiting(); #需要放在前面,否则抓去不准,还有可能会出现下列错误 本次出现这个错误,是因为  .Net Core 跨域 里面的这行:httpContext.Res ...

  5. MappedByteBuffer 写文件

    MappedByteBuffer中"put"和"force"的区别是什么 put()将数据存储在缓冲区中,force()通知操作系统将缓冲区刷新到磁盘. put ...

  6. ThreadPoolExecutor 线程执行超时,释放线程

    如果线程中的执行时间过长,导致长时间被占用,可以通过新建一个子线程,来监控主线程的执行超时时间,如果超时了,通过子线程杀掉父线程 (主意,父线程被杀后,子线程还会活着) 子线程杀掉主线程 这个问题其实 ...

  7. 语音顶会 ICASSP 2022 成果分享:基于时频感知域模型的单通道语音增强算法

    近日,阿里云视频云音频技术团队与新加坡国立大学李海洲教授团队合作论文 <基于时频感知域模型的单通道语音增强算法 >(Time-Frequency Attention for Monaura ...

  8. 【计算机网络】soap和rest简单比较整理

    https://www.bilibili.com/video/BV1ht411U7fC/?spm_id_from=333.337.search-card.all.click&vd_source ...

  9. Python | 使用SVM支持向量机进行鸢尾花分类

    运行环境 Python: 3.7.1 库: sklearn (Python的机器学习工具箱) 目的: 根据鸢尾花的四个特征,对三种鸢尾花进行分类 数据(共150行,这里截取前6行,完整数据以及代码的下 ...

  10. mybatis-plus 对date类型取当天的数据

    数据库中的字段是时间类型,要取出当天的数据,使用mybatis-plus 如何实现,思路是用 时间大于当天凌晨,小于当天23:59:59的时间 //调用的代码Date start = DateUtil ...