简体   繁体   English

在循环内创建 JWT 令牌时,在 jwt-go 中获取相同的令牌

[英]When create JWT token inside loop getting same token in jwt-go

I am creating jwt tokens using jwt-go library.我正在使用 jwt-go 库创建 jwt 令牌。 Later wrote a script to load test.后来写了一个脚本来进行负载测试。 I have noticed when I send the many concurrent request getting same token.我注意到当我发送许多并发请求时获得相同的令牌。 To check more about this I created token inside for loop and result is same.为了检查更多关于这一点,我在 for 循环中创建了令牌,结果是相同的。

The library that I use is https://github.com/dgrijalva/jwt-go , go version is 1.12.9.我使用的库是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)
    }

A JWT contains three parts: a mostly-fixed header , a set of claims , and a signature . JWT 包含三个部分:一个大部分是固定的header 、一组claim和一个签名 RFC 7519 has the actual details. RFC 7519有实际的细节。 If the header is fixed and the claims are identical between two tokens, then the signature will be identical too, and you can easily get duplicated tokens.如果标头是固定的并且两个令牌之间的声明相同,那么签名也将相同,并且您可以轻松获得重复的令牌。 The two timestamp claims "iat" and "exp" are only at a second granularity, so if you issue multiple tokens with your code during the same second you will get identical results (even if you move the expirationTime calculation inside the loop).两个时间戳声明“iat”和“exp”仅处于第二个粒度,因此如果您在同一秒内使用代码发出多个令牌,您将获得相同的结果(即使您将expirationTime计算移动到循环内)。

The jwt-go library exports the StandardClaims listed in RFC 7519 §4.1 as a structure, which is what you're using in your code. jwt-go 库将RFC 7519 §4.1 中列出的StandardClaims作为结构导出,这就是您在代码中使用的内容。 Digging through the library code, there's nothing especially subtle here: StandardClaims uses ordinary "encoding/json" annotations, and then when a token is written out, the claims are JSON encoded and then base64-encoded .仔细研究库代码,这里没有什么特别微妙的地方: StandardClaims使用普通的"encoding/json"注释,然后当写出令牌时,声明是 JSON 编码的,然后是 base64 编码的 So given a fixed input, you'll get a fixed output.所以给定一个固定的输入,你会得到一个固定的输出。

If you want every token to be "different" in some way, the standard "jti" claim is a place to provide a unique ID.如果您希望每个令牌以某种方式“不同”,标准的“jti”声明是提供唯一 ID 的地方。 This isn't part of the StandardClaims, so you need to create your own custom claim type that includes it.这不是 StandardClaims 的一部分,因此您需要创建自己的包含它的自定义声明类型。

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

Then when you create the claims structure, you need to generate a unique TokenId yourself.那么在创建claims结构的时候,就需要自己生成一个唯一的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- has a complete example; https://play.golang.org/p/zDnkamwsCi-有一个完整的例子; every time you run it you will get a different token, even if you run it multiple times in the same second.每次运行它你都会得到一个不同的令牌,即使你在同一秒内多次运行它。 You can base64 decode the middle part of the token by hand to see the claims, or use a tool like the https://jwt.io/ debugger to decode it.您可以手动对令牌的中间部分进行 base64 解码以查看声明,或使用诸如https://jwt.io/调试器之类的工具对其进行解码。

I changed your code:我改变了你的代码:

  • Moved calculation of expirationTime in the loop的移动计算expirationTime在环路
  • Added 1 sec delay on each step of loop在循环的每一步增加 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) }

In this case we get different tokens:在这种情况下,我们得到不同的令牌:

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

Sorry, I am not big expert in JWT and I hope somebody who is explain us this behavior from RFC point of view.抱歉,我不是 JWT 的大专家,我希望有人从 RFC 的角度向我们解释这种行为。

I want to get different tokens.我想获得不同的令牌。 eg : same person login in to system using different browser.例如:同一个人使用不同的浏览器登录系统。 so I want to keep many tokens.所以我想保留很多代币。

It is the same user and we can get him the same token.这是同一个用户,我们可以为他获取相同的令牌。 If we want to give it another one we need to revoke previous one or the client must refresh it.如果我们想再给它一个,我们需要撤销前一个,否则客户端必须刷新它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM