爱摸鱼的Demon
首页
前端知识
后端技术
工程实践
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

爱摸鱼的Demon

我的地盘,欢迎光临。
首页
前端知识
后端技术
工程实践
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • C#

  • Golang

    • Go

    • Gin

      • Gin介绍
      • Gin中的身份认证
        • 一、Cookie
          • 方法定义
        • 二、Session
          • 方法定义
        • 三、Gin Sssion 存储实现
        • 三、JWT(Json Web Token)
          • 1)数据加密和解密
          • 2)登录校验
          • 3)访问使用JWT
        • 四、限流(最常见的保护系统方式)
      • Gin中间件
      • Gin之K8s
    • GORM

  • 后端技术
  • Golang
  • Gin
DemonW-X
2025-09-29
目录

Gin中的身份认证

# 一、Cookie

Cookie 是存储于访问者计算机的浏览器中,可以通过同一个浏览器访问同一个域名时共享数据。Cookie保存在客户浏览器中。

注:http是无状态协议。从一个页面转到另一个页面时,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次访问都是没有任何关系的。

cookie能实现的功能:

1、保持用户登录状态

2、保存用户浏览的历史纪录

3、猜你喜欢,智能推荐

4、电商网站的加入购物车等

# 方法定义

//main.go
func initWebServer() *gin.Engine {
	server := gin.Default()
	//注册中间件,作用于定义在server上的全部路由
	//...
  	//定义cookie
	store := cookie.NewStock([]byte("secret"))
	server.Use(sessions.Sessions("weDemo", store))
	return server
}
1
2
3
4
5
6
7
8
9
10

POST "/users/login"
login success

# 二、Session

Session是另一种记录客户状态的机制;Session保存在服务器上。

工作流程:

客户端浏览器第一次访问服务器并发送请求时,服务器会创建一个session对象,生成一个类似于key,value的键值对,将value保存到服务器,将key返回到浏览器(即客户端)。浏览器下次访问时会携带key(cookie),找到对应的的session(value)。

Gin官方:https://github.com/gin-contrib/sessions (opens new window)

# 方法定义

//web/user.go
func (u *UserHandler) Login(ctx *gin.Context) {
  //一系列判定
  //...
	//登录成功,获取session
	session := sessions.Default(ctx)
	//设置session
	session.Set("userId", user.Id)
	//保存session
	session.Save()
	ctx.String(http.StatusOK, "login success")
}
1
2
3
4
5
6
7
8
9
10
11
12

POST "/users/login"
login success

# 三、Gin Sssion 存储实现

//main.go
func initWebServer() *gin.Engine {
	server := gin.Default()
	//注册中间件,作用于定义在server上的全部路由
	//...
  	//内存memstore
	store := memstore.NewStore([]byte("SPJbeQTIXdpJ7lSzidrOVoWsaEbLdZFB"), []byte("ueFnfGb0JFsvdzeH6ZIu6Oip2cEXVhIR"))
	server.Use(sessions.Sessions("weDemo", store))
	return server
}
1
2
3
4
5
6
7
8
9
10

注意:内存缓存是进程隔离的,所以不同的实例无法使用到相同的Session!

解决办法:负载均衡

# 三、JWT(Json Web Token)

原理:通过加密生成一个token,客户端每次都带上这个token去做访问。

构成部分:

  • Header:头部,JWT的元数据,描述token本身的数据,一个Json对象。
  • Payload:负载,数据内容,一个Json对象。
  • Signature:签名,根据Header和token生成。(用于证明token是否被人为篡改)

JWT文档:https://github.com/golang-jwt/jwt (opens new window)

# 1)数据加密和解密

//web/user.go

func (u *UserHandler) Login(ctx *gin.Context) {
	type LoginForm struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}

	var req LoginForm
	if err := ctx.Bind(&req); err != nil {
		return
	}
	user, err := u.svc.Login(ctx, req.Email, req.Password)
	if err == service.ErrInvalidUserOrPassword {
		ctx.String(http.StatusInternalServerError, err.Error())
		return
	}
	if err != nil {
		ctx.String(http.StatusInternalServerError, "system error : "+err.Error())
		return
	}
	//使用JWT设置登录态
	//生成一个Token
	token := jwt.New(jwt.SigningMethodHS512)
	tokenStr, err := token.SignedString([]byte("SPJbeQTIXdpJ7lSzidrOVoWsaEbLdZFB"))
	//不为空,token不对
	if err != nil {
		ctx.String(http.StatusInternalServerError, "system error : "+err.Error())
		return
	}
	ctx.Header("Authorization", "Bearer "+tokenStr)
	fmt.Println(user)
	ctx.String(http.StatusOK, "login success")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 2)登录校验

//middle/login.go
func (l *LoginMiddlewareBuilder) Build() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		//不需要登录校验的路径
		for _, path := range l.paths {
			if ctx.Request.URL.Path == path {
				return
			}
		}
		//使用token校验
		tokenHeader := ctx.GetHeader("Authorization")
		if tokenHeader == "" {
			//没登录
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		segs := strings.Split(tokenHeader, " ")
		if len(segs) != 2 {
			//没有两段,瞎搞
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		tokenStr := segs[1]
		token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
			return []byte("SPJbeQTIXdpJ7lSzidrOVoWsaEbLdZFB"), nil
		})
		if err != nil {
			//没登陆
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		if token == nil || !token.Valid || claims.Uid == 0 {
			//没登陆
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		//塞入claims
		ctx.Set("claims", claims)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 3)访问使用JWT

//web/user.go
func (u *UserHandler) Profile(ctx *gin.Context) {
	c, ok := ctx.Get("claims")
	//可以断定,必然有claims
	if !ok {
		//监控一下
		ctx.String(http.StatusUnauthorized, "unauthorized: no claims")
		return
	}
	//类型断言
	claims, ok := c.(*UserClaims)
	if !ok {
		ctx.String(http.StatusUnauthorized, "unauthorized: type wrong")
	}

	user, err := u.svc.Profile(ctx, claims.Uid)

	if err != nil {
		ctx.String(http.StatusInternalServerError, "system error : "+err.Error())
	}
	type User struct {
		Nickname        string `json:"nickname"`
		Email           string `json:"email"`
		SelfDescription string `json:"selfDescription"`
		Birthday        string `json:"birthday"`
	}
	ctx.JSON(http.StatusOK, User{
		Nickname:        user.Nickname,
		Email:           user.Email,
		SelfDescription: user.SelfDescription,
		Birthday:        user.Birthday.Format(time.DateOnly),
	})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

优点:

1、不依赖于第三方存储

2、适合在分布式环境下使用

3、提高性能(不需要使用到redis访问)

缺点:

1、对加密的依赖程度大,比Session更容易泄密

2、最好不要在JWT中放置敏感信息(如果真的需要放置,考虑将信息放置在Session中使用,即混用JWT和Session)

# 四、限流(最常见的保护系统方式)

使用原理:限制系统处理的请求数量。

常见算法:滑动窗口,固定窗口计数器,令牌桶,漏桶,自适应限流……

Q:我如何认定谁是谁?我如何确定限流的阈值?

A:使用IP进行限定。(更好的选择是用MAC地址或者设备标识符【CPU序列号】)。

限流的阈值正常应该是通过压测来得到的。

Q:为什么大多的限流都是使用的Redis?

A:限流需要在高并发下快速判断并修改计数器。Redis本身可以持久化状态,并且作为独立于应用的中心化存储,天然支持分布式限流;单线程模型和原子命令(如 INCR、EXPIRE,或 Lua 脚本)完美契合这个需求,能保证计数准确且速度快。

编辑 (opens new window)
上次更新: 2026/04/08, 15:06:55
Gin介绍
Gin中间件

← Gin介绍 Gin中间件→

最近更新
01
Gin之K8s
02-02
02
Gorm之事务
11-13
03
Gorm之关联进阶版
11-13
更多文章>
Theme by Vdoing | Copyright © 2022-2026 爱摸鱼的Demon | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式