Json web token(JWT)golang实现方式

Written by

in

文章目录
  • eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
  • 对头部以及载荷内容进行签名 加密算法对于不同的输入产生的输出总是不一样 对于两个不同的输入,产生同样的输出的概率极其地小 JWT的头部中已经用alg字段指明加密算法 服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应 在JWT中,不应该在载荷里面加入任何敏感的数据,比如用户的密码
  • 一般是在请求头里加入Authorization,并加上Bearer标注 fetch(‘api/user/1’, { headers: {‘Authorization’: ‘Bearer ‘ + token }})服务端会验证token 如果验证通过,就会返回相应的资源
  • 调用包 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 中的 json 编解码深度解析 golang中encoding/json包的实现 Golang实现读取excel文件并转换为JSON格式 golang MarshalJson的实现 golang通过反射手动实现json序列化的方法 golang JSON技巧小结 Golang中自定义json序列化时间格式的示例代码
  • 目录
    • Json web token (JWT)
    • 三部分构成
      • 第一部头部(header)的作用​​​​​
      • 第二部分载荷(payload)
      • 第三部分签证(signature)
    • 签名的目的
      • 如何应用
        • Golang 客户端实现
          • 总结

            eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
            

            声明类型

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

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

            将头部进行base64加密

            eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
            

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

            标准中注册的声明

            • 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
            

            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

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

            调用包 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 中的 json 编解码深度解析
            • golang中encoding/json包的实现
            • Golang实现读取excel文件并转换为JSON格式
            • golang MarshalJson的实现
            • golang通过反射手动实现json序列化的方法
            • golang JSON技巧小结
            • Golang中自定义json序列化时间格式的示例代码

            站内搜索