乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

    • Golang基础知识

    • Golang进阶知识

    • Golang常用包

    • Gin框架

      • 安装
      • gin路由
      • 请求数据参数绑定
      • gin渲染
      • 使用模板渲染
      • 静态文件的使用
      • 数据渲染
      • gin重定向
      • gin同步和异步
      • go中间件
      • 会话保持
      • 文件上传
      • JWT的简单使用
        • JWT 的构成
          • Header
          • Playload
          • Signature
        • 示例代码
          • 生成 token
          • 解析 token
          • 注册或者登录的时候发放 token
          • 定义中间件来进行认证
      • 模板函数
      • Swagger
      • API访问控制
      • 常见的应用中间件
      • 应用配置管理
      • 优雅停止与重启
      • 集成Casbin进行访问权限控制
  • AIOps

  • Python

  • DevOps

  • 专栏
  • Golang
  • Gin框架
乔克
2025-07-19
目录

JWT的简单使用

JWT 是 json web token 的缩写,它将用户信息加密到 token 中,然后返回给 client,client 在下次请求的时候带上 token 即可。

# JWT 的构成

# Header

JWT 的 header 由两部分组成:

  • 类型
  • 加密算法
# Playload

playload 可以填充两种类型数据

1.标准中注册的声明:

iss: 签发者
sub: 面向的用户
aud: 接收方
exp: 过期时间
nbf: 生效时间
iat: 签发时间
jti: 唯一身份标识
1
2
3
4
5
6
7

2.自定义数据

# Signature

签名的算法:

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)
1
2
3
4
5

# 示例代码

# 生成 token
// 加密的key
var jwtKey = []byte("secret_key")

type claims struct {
	UserID uint
	jwt.StandardClaims
}

// 生成token
func GenerateToken(user model.User)(string,error){
	expireTime := time.Now().Add(7*24*time.Hour)
	newClaim := claims{
		UserID:         user.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			IssuedAt: time.Now().Unix(),
			Issuer: "joker",
			Subject: "user token",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256,newClaim)
	tokenString,err := token.SignedString(jwtKey)
	if err != nil {
		return "",err
	}
	return tokenString, nil
}
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
# 解析 token
// 解析Token
func ParseToken(tokenString string)(*jwt.Token,*claims,error){
	newClaim := &claims{}
	token, err := jwt.ParseWithClaims(tokenString,newClaim, func(token *jwt.Token) (i interface{}, err error) {
		return jwtKey,err
	})
	return token,newClaim,err
}
1
2
3
4
5
6
7
8
# 注册或者登录的时候发放 token
func Register(ctx *gin.Context) {
	db := common.GetDB()
	// 获取注册数据
	name := ctx.PostForm("name")
	password := ctx.PostForm("password")
	telephone := ctx.PostForm("telephone")
	// 校验用户名、密码、手机号码
	// 手机号码必须是11位,如果手机号存在则返回已注册
	// 密码不能为空
	// 用户名如果为空,则生成十位随机字符串作为用户名

	if len(telephone) != 11 || len(telephone) == 0 {
		response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"手机号不能为空或者必须是11位")
		return
	}

	if len(password) == 0 {
		response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"密码不能为空")
		return
	}

	if len(name) == 0 {
		name = utils.RandomString(10)
		fmt.Println(name)
	}
	// 数据库中查找手机号是否存在,如果存在,则返回已注册
	if isTelephoneExist(db, telephone) {
		response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"手机号码已被注册")
		return
	}

	// 密码加密
	hasePassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		response.Response(ctx,http.StatusInternalServerError, 500,nil,"密码加密失败")
		return
	}
	// 开始注册
	newUser := model.User{
		UserName:  name,
		PassWord:  string(hasePassword),
		Telephone: telephone,
	}
	db.Create(&newUser)

	// 生成token
	token, err := common.GenerateToken(newUser)
	if err != nil {
		ctx.JSON(500, gin.H{
			"code": 500,
			"msg":  "系统错误",
		})
		response.Response(ctx,http.StatusInternalServerError, 500,nil,"系统错误")
		log.Println("generate token failed. err : " + err.Error())
		return
	}
	// 注册成功
	response.Success(ctx,gin.H{"token":token,},"注册成功")
}
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 定义中间件来进行认证
// 用户认证的中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 从请求中获取Authorization
		tokenString := ctx.GetHeader("Authorization")
		fmt.Println(tokenString)
		// 判断Authorization是否合法
		if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer"){
			ctx.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg": "权限不足",
			})
			ctx.Abort()
			return
		}
		log.Println("Authorization 合法")
		// 解析Authorization
		tokenString = tokenString[7:]
		token, claims, err := common.ParseToken(tokenString)
		if err != nil || !token.Valid {
			ctx.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg": "权限不足",
			})
			ctx.Abort()
			return
		}
		log.Println("token 解析成功")
		// 获取user信息
		userId := claims.UserID
		db := common.GetDB()
		var user model.User
		db.First(&user,userId)

		// 用户不存在,返回401
		if user.ID == 0{
			ctx.JSON(http.StatusUnauthorized,gin.H{
				"code":401,
				"msg": "权限不足",
			})
			ctx.Abort()
			return
		}
		// 用户存在,写入上下文
		ctx.Set("user",user)
		ctx.Next()
	}
}

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
41
42
43
44
45
46
47
48
49

作者:乔克

本文链接:https://jokerbai.com

版权声明:本博客所有文章除特别声明外,均采用 署名-非商业性-相同方式共享 4.0 国际 (CC-BY-NC-SA-4.0) 许可协议。转载请注明出处!

上次更新: 2025/07/19, 09:17:41
文件上传
模板函数

← 文件上传 模板函数→

最近更新
01
使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建
07-19
02
使用Zadig从0到1实现持续交付平台
07-19
03
基于Jira的运维发布平台
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式