当在循环内创建jwt令牌时在jwt-go中获得相同的令牌

时间:2019-08-31 06:08:41

标签: go jwt

我正在使用jwt-go库创建jwt令牌。后来写了一个脚本来进行负载测试。我注意到当我发送多个并发请求时获得相同的令牌。为了检查更多信息,我在for循环内创建了令牌,结果是相同的。

我使用的库是https://github.com/dgrijalva/jwt-go,go版本是1.12.9。

expirationTime := time.Now().Add(time.Duration(60) * time.Minute)

    for i := 1; i < 5; i++ {
        claims := &jwt.StandardClaims{
            ExpiresAt: expirationTime.Unix(),
            Issuer:"telescope",
        }
        _token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        var jwtKey = []byte("secret_key")
        auth_token, _ := _token.SignedString(jwtKey)
        fmt.Println(auth_token)
    }

2 个答案:

答案 0 :(得分:2)

JWT包含三个部分:一个大部分是固定的 header ,一组 claims 和一个 signature RFC 7519包含实际详细信息。如果标头是固定的,并且两个令牌之间的声明相同,那么签名也将相同,并且您可以轻松获得重复的令牌。这两个时间戳声明“ iat”和“ exp”仅在第二个粒度上,因此,如果您在同一秒钟内用代码发布多个令牌,您将得到相同的结果(即使您将expirationTime计算移至循环)。

jwt-go库将StandardClaims中列出的RFC 7519 §4.1导出为结构,这是您在代码中使用的结构。浏览库代码,这里没有什么特别微妙的地方:StandardClaims使用普通的"encoding/json"注释,然后在写出令牌时使用the claims are JSON encoded and then base64-encoded。因此,给定固定的输入,您将得到固定的输出。

如果您希望每个令牌都以某种方式“不同”,则the standard "jti" claim是提供唯一ID的地方。这不是StandardClaims的一部分,因此您需要创建一个包含它的自定义声明类型。

type UniqueClaims struct {
    jwt.StandardClaims
    TokenId string `json:"jti,omitempty"`
}

然后,在创建声明结构时,您需要自己生成唯一的TokenId

import (
    "crypto/rand"
    "encoding/base64"
)

bits := make([]byte, 12)
_, err := rand.Read(bits)
if err != nil {
    panic(err)
}
claims := UniqueClaims{
    StandardClaims: jwt.StandardClaims{...},
    TokenId: base64.StdEncoding.EncodeToString(bits),
}

https://play.golang.org/p/zDnkamwsCi-有一个完整的示例;每次运行它都将获得一个不同的令牌,即使您在同一秒内多次运行它也是如此。您可以手工对令牌的中间部分进行base64解码以查看声明,或使用https://jwt.io/调试器之类的工具对其进行解码。

答案 1 :(得分:0)

我更改了您的代码:

  • 在循环中移动expirationTime的计算
  • 循环的每一步都增加了1秒的延迟

    for i := 1; i < 5; i++ {
    
        expirationTime := time.Now().Add(time.Duration(60) * time.Minute)
    
        claims := &jwt.StandardClaims{
            ExpiresAt: expirationTime.Unix(),
            Issuer:    "telescope",
        }
        _token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        var jwtKey = []byte("secret_key")
        auth_token, _ := _token.SignedString(jwtKey)
        fmt.Println(auth_token)
    
        time.Sleep(time.Duration(1) * time.Second)
    }
    

在这种情况下,我们获得了不同的令牌:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjcyNDcwNDgsImlzcyI6InRlbGVzY29wZSJ9.G7wV-zsCYjysLEdgYAq_92JGDPsgqqOz9lZxdh5gcX8
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjcyNDcwNDksImlzcyI6InRlbGVzY29wZSJ9.yPNV20EN3XJbGiHhe-wGTdiluJyVHXj3nIqEsfwDZ0Q
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjcyNDcwNTAsImlzcyI6InRlbGVzY29wZSJ9.W3xFXEiVwh8xK47dZinpXFpKuvUl1LFUAiaLZZzZ2L0
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjcyNDcwNTEsImlzcyI6InRlbGVzY29wZSJ9.wYUbzdXm_VQGdFH9RynAVVouW9h6KI1tHRFJ0Y322i4

抱歉,我不是JWT的专家,我希望有人从RFC的角度向我们解释这种行为。

  

我想获得其他令牌。例如:同一个人使用不同的浏览器登录系统。所以我想保留很多令牌。

是同一用户,我们可以为他获得相同的令牌。如果要再给它一个,我们需要撤消前一个,否则客户端必须刷新它。