🏷️ 标签:Go Gin 会话控制 Cookie Session 登录认证 中间件 Web开发 📝 适用人群:Go 初学者、Gin 框架开发者、课程实训、作业报告、面试必背 💡 文章亮点:全网最细、逐行注释、通俗易懂、无任何省略、可直接运行,从 HTTP 无状态讲到 Cookie 原理、Session 原理、完整登录实战、拦截器、生命周期、安全配置,新手也能完全学会!


一、前言:为什么需要会话控制?

1.1 HTTP 协议是无状态的

HTTP 协议不会记住用户身份,每一次请求对服务器来说都是 “陌生人”。

这会导致:

  • 登录后刷新页面 → 又要重新登录
  • 无法保存用户信息
  • 无法实现购物车、权限判断、后台管理

1.2 会话控制是什么?

会话控制 = 让服务器记住当前用户。 从用户打开网站 → 登录 → 操作 → 关闭网站,整个过程保持登录状态,这就是会话控制。

1.3 Gin 中两种会话方案

  1. Cookie:数据存在浏览器(客户端)
  2. Session:数据存在服务器(服务端)

二、Cookie 超详细讲解(客户端存储)

2.1 什么是 Cookie?

  • Cookie 是服务器写给浏览器的一小段文本数据
  • 浏览器自动保存
  • 下次请求同一网站时自动携带
  • 键值对格式,有过期时间
  • 大小限制约 4KB
  • 不安全(可查看、可篡改)

2.2 Cookie 工作流程

  1. 浏览器请求服务器
  2. 服务器通过响应头返回 Set-Cookie
  3. 浏览器保存 Cookie
  4. 下次请求自动在请求头带上 Cookie
  5. 服务器读取 Cookie 识别用户

2.3 Gin 中 Cookie 所有用法(逐行详解)

2.3.1 设置 Cookie(最全参数)
// 设置 Cookie
r.GET("/setCookie", func(c *gin.Context) {
	/*
		参数说明(共7个,必须记)
		1. name      Cookie 名称
		2. value     Cookie 值
		3. maxAge    有效时间(秒) 60*60*24 = 1天
		4. path      生效路径 / 表示全站有效
		5. domain    域名 空表示当前域名
		6. secure    是否仅HTTPS生效 false=http/https都可以
		7. httpOnly  是否仅http可访问(true=JS无法读取,更安全)
	*/
	c.SetCookie("username", "Gin-Student", 60*60*24, "/", "", false, true)

	c.String(200, "✅ Cookie 设置成功!名称:username,值:Gin-Student")
})
2.3.2 获取 Cookie
r.GET("/getCookie", func(c *gin.Context) {
	// 根据名称获取 Cookie
	username, err := c.Cookie("username")

	// 判断是否获取成功
	if err != nil {
		c.String(200, "❌ 未找到 Cookie 或已过期")
		return
	}

	c.String(200, "✅ 获取到Cookie:username = "+username)
})
2.3.3 删除 Cookie

原理:把有效时间设置为 -1,浏览器会自动删除

r.GET("/delCookie", func(c *gin.Context) {
	// 参数必须和设置时一致(除了value和maxAge)
	c.SetCookie("username", "", -1, "/", "", false, true)
	c.String(200, "✅ Cookie 已删除")
})

2.4 Cookie 优点与缺点

优点:

  • 简单、轻量
  • 服务器无需存储
  • 自动携带

缺点:

  • 不安全(可查看、可篡改)
  • 容量小(4KB)
  • 受跨域限制
  • 不能存敏感信息(密码、身份证)

三、Session 超详细讲解(服务端存储)

3.1 什么是 Session?

  • Session 是服务器端的会话存储
  • 每个用户拥有独立的 Session
  • 基于 Cookie 实现(浏览器只存一个 sessionId
  • 安全、容量大、适合存登录信息

3.2 Session 工作流程

  1. 登录成功
  2. 服务器创建 Session,保存用户信息
  3. 服务器返回 sessionId 到浏览器 Cookie
  4. 后续请求自动携带 sessionId
  5. 服务器通过 sessionId 找到对应用户信息

3.3 Gin 集成 Session(企业标准)

3.3.1 安装依赖
go get github.com/gin-contrib/sessions
go get github.com/gin-contrib/sessions/cookie
3.3.2 初始化 Session(必须写在最前面)
package main

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

func main() {
	// 1. 创建 Gin 路由
	r := gin.Default()

	// 2. 创建 Session 存储引擎(参数是密钥,必须写,用于加密)
	store := cookie.NewStore([]byte("my-secret-key-123456789"))

	// 3. 设置 Session 配置(可选,企业常用)
	store.Options(sessions.Options{
		MaxAge:   86400, // 有效期 1天(秒)
		Path:     "/",   // 全路径生效
		HttpOnly: true,  // 禁止JS读取,安全
		Secure:   false, // 是否HTTPS
	})

	// 4. 注册 Session 中间件
	// 参数1:Cookie 名称(自定义)
	// 参数2:存储引擎
	r.Use(sessions.Sessions("my-gin-session", store))

	// ———————————— 路由写下面 ————————————

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

四、Session 完整实战:登录、判断、拦截、退出

4.1 登录接口(设置 Session)

// 登录:验证账号密码,设置 Session
r.GET("/login", func(c *gin.Context) {
	// 1. 获取前端传入的账号密码(真实项目用POST)
	username := c.Query("username")
	password := c.Query("password")

	// 2. 模拟验证(真实项目查数据库)
	if username == "admin" && password == "123456" {
		// 3. 获取 Session 对象
		s := sessions.Default(c)

		// 4. 设置登录信息(可存任意多个)
		s.Set("userId", 1001)          // 用户ID
		s.Set("username", username)    // 用户名
		s.Set("role", "admin")         // 角色

		// 5. 保存 Session(必须调用!)
		s.Save()

		c.JSON(200, gin.H{
			"code":    200,
			"message": "✅ 登录成功",
		})
		return
	}

	c.JSON(200, gin.H{
		"code":    400,
		"message": "❌ 账号或密码错误",
	})
})

4.2 获取用户信息(判断是否登录)

// 获取当前登录用户信息
r.GET("/user/info", func(c *gin.Context) {
	// 1. 获取 Session
	s := sessions.Default(c)

	// 2. 读取数据
	userId := s.Get("userId")
	username := s.Get("username")
	role := s.Get("role")

	// 3. 判断是否登录
	if userId == nil {
		c.JSON(200, gin.H{
			"code":    401,
			"message": "❌ 未登录,请先登录",
		})
		return
	}

	// 4. 返回用户信息
	c.JSON(200, gin.H{
		"code":     200,
		"message":  "✅ 获取成功",
		"userId":   userId,
		"username": username,
		"role":     role,
	})
})

4.3 退出登录(销毁 Session)

// 退出登录:清空 Session
r.GET("/logout", func(c *gin.Context) {
	s := sessions.Default(c)

	// 清空所有数据
	s.Clear()

	// 销毁 Session
	s.Delete("userId")
	s.Delete("username")

	// 保存修改
	s.Save()

	c.JSON(200, gin.H{
		"code":    200,
		"message": "✅ 退出登录成功",
	})
})

五、企业实战:登录拦截中间件(必学)

5.1 编写登录验证中间件

// 登录认证中间件:所有需要登录的接口必须经过这里
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 获取 Session
		s := sessions.Default(c)
		userId := s.Get("userId")

		// 2. 判断是否登录
		if userId == nil {
			// 返回JSON提示
			c.JSON(200, gin.H{
				"code":    401,
				"message": "❌ 未登录,请先登录",
			})

			// 终止请求,不继续执行接口
			c.Abort()
			return
		}

		// 3. 已登录,放行
		c.Next()
	}
}

5.2 使用中间件保护接口

// 需要登录才能访问的路由组
authRouter := r.Group("/admin")
// 使用中间件
authRouter.Use(AuthMiddleware())
{
	authRouter.GET("/dashboard", func(c *gin.Context) {
		c.String(200, "✅ 后台首页(已登录)")
	})

	authRouter.GET("/user/list", func(c *gin.Context) {
		c.String(200, "✅ 用户列表(已登录)")
	})
}

六、Session 生命周期与安全配置(超详细)

6.1 设置 Session 有效期

store.Options(sessions.Options{
	MaxAge:   86400,   // 1天
	Path:     "/",      // 生效路径
	HttpOnly: true,     // 禁止JS读取
	Secure:   false,    // 生产环境改为true(HTTPS)
	SameSite: http.SameSiteStrictMode, // 防CSRF攻击
})

6.2 Session 常用方法大全

s := sessions.Default(c)

// 设置
s.Set("key", value)

// 获取
s.Get("key")

// 删除
s.Delete("key")

// 清空全部
s.Clear()

// 保存(必须)
s.Save()

七、Cookie 与 Session 对比(面试必背)

对比项 Cookie Session
存储位置 浏览器(客户端) 服务器
安全性 低(可查看、可篡改) 高(安全)
存储大小 小(4KB) 大(无限制)
依赖 Cookie 自身就是 Cookie 依赖 Cookie 存 sessionId
服务器压力 占用服务器内存
适用场景 记住账号、主题、非敏感数据 登录状态、权限、用户信息

八、企业开发最佳实践

  1. 登录状态必须用 Session,不要用 Cookie
  2. Cookie 只存非敏感信息
  3. Session 开启 HttpOnly 防止 XSS
  4. Session 有效期设置 1 天
  5. 所有后台接口必须使用登录拦截中间件
  6. 退出登录必须清空 Session
  7. 生产环境使用 HTTPS

九、完整可运行代码(复制即用)

package main

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

// 登录中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		s := sessions.Default(c)
		userId := s.Get("userId")
		if userId == nil {
			c.JSON(200, gin.H{"code": 401, "msg": "未登录"})
			c.Abort()
			return
		}
		c.Next()
	}
}

func main() {
	r := gin.Default()

	// Session 初始化
	store := cookie.NewStore([]byte("secret123456"))
	store.Options(sessions.Options{
		MaxAge:   86400,
		HttpOnly: true,
	})
	r.Use(sessions.Sessions("mysession", store))

	// Cookie 示例
	r.GET("/setCookie", func(c *gin.Context) {
		c.SetCookie("username", "test", 60*60*24, "/", "", false, true)
		c.String(200, "设置Cookie成功")
	})
	r.GET("/getCookie", func(c *gin.Context) {
		val, _ := c.Cookie("username")
		c.String(200, "获取到:"+val)
	})

	// Session 登录
	r.GET("/login", func(c *gin.Context) {
		s := sessions.Default(c)
		s.Set("userId", 1001)
		s.Set("username", "admin")
		s.Save()
		c.JSON(200, gin.H{"msg": "登录成功"})
	})

	// 获取信息
	r.GET("/user/info", func(c *gin.Context) {
		s := sessions.Default(c)
		user := s.Get("username")
		if user == nil {
			c.JSON(200, gin.H{"msg": "未登录"})
			return
		}
		c.JSON(200, gin.H{"user": user})
	})

	// 退出
	r.GET("/logout", func(c *gin.Context) {
		s := sessions.Default(c)
		s.Clear()
		s.Save()
		c.JSON(200, gin.H{"msg": "退出成功"})
	})

	// 受保护路由
	admin := r.Group("/admin")
	admin.Use(AuthMiddleware())
	{
		admin.GET("/data", func(c *gin.Context) {
			c.String(200, "敏感数据")
		})
	}

	r.Run(":8080")
}

十、总结(超清晰)

  1. HTTP 无状态 → 必须用会话控制
  2. Cookie 存在浏览器,不安全,存少量数据
  3. Session 存在服务器,安全,适合登录
  4. Gin 使用 gin-contrib/sessions 实现 Session
  5. 登录流程:验证账号 → 设置 Session → 保存
  6. 中间件实现统一登录拦截
  7. 退出登录:清空 Session + 保存
  8. 企业开发:登录用 Session,普通配置用 Cookie

版权声明

本文为原创 Go 语言 Gin 会话控制 超详细教程,逐行讲解、无省略、无门槛、可直接用于课程实训、作业、面试、企业开发,禁止未经授权转载抄袭。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐