Json web token(JWT)golang实现方式

 更新时间:2025年11月17日 16:05:24   作者:一条闲鱼_mytube  
JWT由三部分组成:头部、载荷和签证,头部包含类型和加密算法;载荷包含声明;签证通过头部和载荷与密钥生成,JWT用于身份验证和信息交换,在Golang中,可以使用包https://github.com/tutengdihuang/jwt来实现JWT的生成、验证和解码

Json web token (JWT)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

三部分构成

第一部头部(header)的作用​​​​​

声明类型

声明加密的算法 通常直接使用 HMAC SHA256

{'typ': 'JWT','alg': 'HS256'}

将头部进行base64加密

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

第二部分载荷(payload)

载荷就是存放有效信息的地方:

标准中注册的声明

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击

公共的声明

  • 公共的声明可以添加任何的信息
  • 一般添加用户的相关信息或其他业务需要的必要信息
  • 议添加敏感信息,因为该部分在客户端可解密

私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

  • 举例:
{"sub": "1234567890","name": "John Doe","admin": true}然后将其进行base64加密,得到Jwt的第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9signature

第三部分签证(signature)

UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
  • header (base64后的)
  • payload (base64后的)
  • secret
  • 需要base64加密后的header和base64加密后的payload使用"."连接组成的字符串(头部在前),
  • 然后通过header中声明的加密方式进行加secret组合加密,
  • 构成了jwt的第三部分
  • 举例
  • secret 需要保存在服务端用来生成token和验证

签名的目的

  • 对头部以及载荷内容进行签名
  • 加密算法对于不同的输入产生的输出总是不一样
  • 对于两个不同的输入,产生同样的输出的概率极其地小
  • JWT的头部中已经用alg字段指明加密算法
  • 服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应
  • 在JWT中,不应该在载荷里面加入任何敏感的数据,比如用户的密码

如何应用

一般是在请求头里加入Authorization,并加上Bearer标注

fetch('api/user/1', { headers: {'Authorization': 'Bearer ' + token }})服务端会验证token

如果验证通过,就会返回相应的资源

Golang 客户端实现

调用包 https://github.com/tutengdihuang/jwt

  • 单例模式
var jwtIns *JwtAuth

type JwtAuth struct {
	Lock      *sync.Mutex
	algorithm *jwt.Algorithm
	claimsMap map[string]*jwt.Claims //key: userID
}

func GetJwtAuth() *JwtAuth {
	if jwtIns == nil {
		once := sync.Once{}
		once.Do(
			func() {
				if jwtIns == nil {
					jwtIns = new(JwtAuth)
					jwtIns.Lock = new(sync.Mutex)
					jwtIns.claimsMap = make(map[string]*jwt.Claims)
					secret := config_center.GetViperConf().Sub("jwt").GetString("secret")
					algorithm := jwt.HmacSha256(secret)
					jwtIns.algorithm = &algorithm
				}
			})
	}
	return jwtIns
}
  • get token
var jwtClaimUserKey = "username"
var jwtClaimUserIdKey = "id"

func (this *JwtAuth) GetToken(userName string, id int) (token string, err error) {
	claim := jwt.NewClaim()
	claim.Set(jwtClaimUserKey, userName)
	claim.Set(jwtClaimUserIdKey, strconv.Itoa(id))
	//claim.SetTime("expire", time.Now().Add(30*time.Minute))
	idstr := strconv.Itoa(id)
	this.Lock.Lock()
	defer this.Lock.Unlock()
	this.claimsMap[idstr] = claim
	token, err = this.algorithm.Encode(claim)
	return
}
  • validate check
func (this *JwtAuth) Validate(idstr, token string) bool {
	this.Lock.Lock()
	defer this.Lock.Unlock()
	if _, ok := this.claimsMap[idstr]; !ok {
		return false
	}
	if this.algorithm.Validate(token) != nil {
		return false
	}

	return true
}
  • token decode
func (this *JwtAuth) TokenDecode(token string) (string, int, error) {
	claim, err := this.algorithm.Decode(token)
	if err != nil {
		return "", 0, err
	}
	userName, err := claim.Get(jwtClaimUserKey)
	if err != nil {
		return "", 0, err
	}
	idStr, err := claim.Get(jwtClaimUserIdKey)
	if err != nil {
		return "", 0, err
	}
	id, _ := strconv.Atoi(idStr)
	return userName, id, nil
}
  • token remove
func (this *JwtAuth) TokenRemove(id string) {
	this.Lock.Lock()
	defer this.Lock.Unlock()
	delete(this.claimsMap, id)
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • golang连接池检查连接失败时如何重试(示例代码)

    golang连接池检查连接失败时如何重试(示例代码)

    在Go中,可以通过使用database/sql包的DB类型的Ping方法来检查数据库连接的可用性,本文通过示例代码,演示了如何在连接检查失败时进行重试,感兴趣的朋友一起看看吧
    2023-10-10
  • Golang通过SSH执行交换机操作实现

    Golang通过SSH执行交换机操作实现

    这篇文章主要介绍了Golang通过SSH执行交换机操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • golang中"var"与":="的区别解析

    golang中"var"与":="的区别解析

    这篇文章主要介绍了golang中“var”与“:=”的区别,使用var关键字是Go最基本的定义变量方式,有时也会使用到:=来定义变量,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Golang Gorm 更新字段save、update、updates

    Golang Gorm 更新字段save、update、updates

    在gorm中,批量更新操作可以通过使用Update方法来实现,本文主要介绍了Golang Gorm 更新字段save、update、updates,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • windows下使用vscode搭建golang环境并调试的过程

    windows下使用vscode搭建golang环境并调试的过程

    这篇文章主要介绍了在windows下使用vscode搭建golang环境并进行调试,主要包括安装方法及环境变量配置技巧,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • Go 实现基于Token 的登录流程深度分析

    Go 实现基于Token 的登录流程深度分析

    Token 认证机制的核心思想是,服务端在用户登录时生成一个 Token,客户端在后续的请求中携带这个 Token,服务端通过验证 Token 的有效性来确认用户的身份,本文将带你深入探索基于 Token 的登录流程,这是一种更为灵活且适用于现代应用架构的认证方式
    2024-03-03
  • 详解Go语言的计时器

    详解Go语言的计时器

    Go语言的标准库里提供两种类型的计时器Timer和Ticker。这篇文章主要介绍了Go语言的计时器的相关知识,需要的朋友可以参考下
    2020-05-05
  • 一文详解go同步协程的必备工具WaitGroup

    一文详解go同步协程的必备工具WaitGroup

    这篇文章主要为大家介绍了一文详解go同步协程的必备工具WaitGroup使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Go高级特性探究之HTTP错误处理详解

    Go高级特性探究之HTTP错误处理详解

    在Web应用程序中,HTTP错误处理是非常重要的,它关系到Web应用程序的稳定性和可靠性,本文介绍如何在Go项目中处理HTTP错误,并提供相应的解决方案和实践经验,希望对Go语言Web应用程序的开发者有所帮助
    2023-06-06
  • Go语言实现多文本文件合并的示例代码

    Go语言实现多文本文件合并的示例代码

    这篇文章主要为大家详细介绍了使用Go语言实现多文本文件合并的相关知识,适用于初学者学习文件读取与写入的综合运用,有需要的小伙伴可以了解下
    2025-07-07

最新评论