如何使用TinyGo解码JWT令牌

huangapple go评论97阅读模式
英文:

How to decode a JWT token with TinyGo

问题

我们有一个JWT令牌需要解码,问题是我们正在使用TinyGo,并且一些库是不受支持的。如何在已经支持的TinyGo / Go核心库中完成解码?我想要打印出"name"的值:

func main() {
    token := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`
    base64String := base64.StdEncoding.EncodeToString([]byte(token))
    decodedData, err := base64.StdEncoding.DecodeString(base64String)
    if err != nil {
        panic(err)
    }

    name := decodedData["name"]

    fmt.Println(name)
}

解码后的令牌是:

PAYLOAD
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

https://jwt.io查看此示例令牌。

英文:

We have a JWT token that we need to decode, the issue is that we are using TinyGo and some libraries are not supported,
How can it be done for TinyGo / core Go libraries which is already supported? I want to print the "name" value:

I'm not able to get the name, any idea?

func main() {
	token := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`
	base64String := base64.StdEncoding.EncodeToString([]byte(token))
	decodedData, err := base64.StdEncoding.DecodeString(base64String)
	if err != nil {
		panic(err)
	}

	name := decodedData["name"]

	fmt.Println(name)

}

The decoded token is:

PAYLOAD
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

See this example token from https://jwt.io

答案1

得分: 3

解码并获取name部分很容易。但这并不能确保令牌是有效的,也就是说令牌的所有者确实是所声明的名字!

JWT 令牌只包含头部、负载和签名部分的 base64 编码形式,用 . 连接起来。所以只需按 . 分割令牌,解码 base64 字符串,然后可以使用 json.Unmarshal() 将头部和负载部分转换为映射或结构体。

你必须验证签名以确保名字是有效的。如果不进行签名验证,令牌很容易被伪造成任何人。签名验证正是 JWT 库所做的事情(除了解析和生成令牌)。如何进行签名验证,请查看 JWT 库的源代码。我还相信有一些开源库可以处理 JWT 令牌,也可以与 tiny-go 一起使用。

以下是解码各部分并打印 name 的示例代码:

token := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`
for i, part := range strings.Split(token, ".") {
    fmt.Printf("[%d] part: %s\n", i, part)
    decoded, err := base64.RawURLEncoding.DecodeString(part)
    if err != nil {
        panic(err)
    }
    fmt.Println("decoded:", string(decoded))
    if i != 1 {
        continue // i == 1 is the payload
    }

    var m map[string]interface{}
    if err := json.Unmarshal(decoded, &m); err != nil {
        fmt.Println("json decoding failed:", err)
        continue
    }
    if name, ok := m["name"]; ok {
        fmt.Println("name:", name)
    }
}

Go Playground 上运行上述代码会输出:

[0] part: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
decoded: {"alg":"HS256","typ":"JWT"}
[1] part: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
decoded: {"sub":"1234567890","name":"John Doe","iat":1516239022}
name: John Doe
[2] part: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
decoded: I�J�IHNJ(]�O���lj~�:N�%_�u,×
英文:

Decoding and getting the name part is easy. But this does not ensure the token is valid, meaning the owner of the token is truly what the name says!

JWT tokens just contain the base64 encoded forms of a header, payload and signature parts, connected with a .. So just split the token by ., decode the base64 string and you may use json.Unmarshal() to convert the header and playload parts to maps or structs.

You must verify the signature to ensure the name is valid. If you don't perform signature verification, a token may easily be forged to pose as anyone. Signature verification is exactly what JWT libs do (besides parsing and generating tokens). How to do that, check the sources of JWT libs. I also believe there are open-source libs that process JWT tokens that also work with tiny-go.

Example code to decode the parts and print the name:

token := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`
for i, part := range strings.Split(token, ".") {
	fmt.Printf("[%d] part: %s\n", i, part)
	decoded, err := base64.RawURLEncoding.DecodeString(part)
	if err != nil {
		panic(err)
	}
	fmt.Println("decoded:", string(decoded))
	if i != 1 {
		continue // i == 1 is the payload
	}

	var m map[string]interface{}
	if err := json.Unmarshal(decoded, &m); err != nil {
		fmt.Println("json decoding failed:", err)
		continue
	}
	if name, ok := m["name"]; ok {
		fmt.Println("name:", name)
	}
}

Which outputs (try it on the Go Playground):

[0] part: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
decoded: {"alg":"HS256","typ":"JWT"}
[1] part: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
decoded: {"sub":"1234567890","name":"John Doe","iat":1516239022}
name: John Doe
[2] part: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
decoded: I�J�IHNJ(]�O���lj~�:N�%_�u,×

huangapple
  • 本文由 发表于 2021年6月28日 17:38:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/68161012.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定