base64 解析jwt

参见: python: base64解析jwt的Payload

示例代码:

package main

import (
	"encoding/base64"
	"fmt"
	"strings"
)

func main() {
	s := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiRGluZXNoIn0.0Cbf0JnPzCkPepFOGijYoCv807h4zgKYMk4GjAlXKBI"
	sArr := strings.Split(s, ".")
	payload := sArr[1]

	suffix := strings.Repeat("=", (4 - len(payload)%4))
	payload += suffix
	fmt.Println(payload)

	d, err := base64.URLEncoding.DecodeString(payload)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(d))
}

输出:

eyJuYW1lIjoiRGluZXNoIn0=
{"name":"Dinesh"}

解析jwt到struct

NG验证jwt方法。

代码:

package main

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"
)

type jwtInfo struct {
	Exp     int64 `json:"exp"`
	Iat     int64 `json:"iat"`
	expTime time.Time
}

func parseJwtPayload(jwt string) (*jwtInfo, error) {
	sArr := strings.Split(jwt, ".")
	if len(sArr) != 3 {
		err := errors.New(fmt.Sprintf("Invalid JWT: %s", jwt))
		panic(err)
	}
	payload := sArr[1]
	suffix := strings.Repeat("=", (4 - len(payload)%4))
	if len(suffix) != 4 {
		payload += suffix
	}

	println(payload)
	d, err := base64.URLEncoding.DecodeString(payload)
	if err != nil {
		panic(err)
	}
	info := &jwtInfo{}
	err = json.Unmarshal(d, info)
	if err != nil {
		panic(err)
	}
	return info, nil
}

func main() {

	jwt := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDIxMTI5NDgsImlhdCI6MTcwMjAyNjU0OCwiaXNzIjoid2wiLCJhdXRoRGF0YSI6eyJpZCI6MiwidXNlcm5hbWUiOiJuZy1kZW1vIn19.T1jEV5wzd9g1aCmmP5gFlw_PuPBoGlVVRUSqHJXJ0p4"

	jwtInfo, _ := parseJwtPayload(jwt)

	exp := time.Unix(jwtInfo.Exp, 0)
	fmt.Println(exp.Format("2006-01-02 15:04:05"))
	t := time.Since(exp)
	fmt.Println(t, t > 0)
}

输出:

eyJleHAiOjE3MDIxMTI5NDgsImlhdCI6MTcwMjAyNjU0OCwiaXNzIjoid2wiLCJhdXRoRGF0YSI6eyJpZCI6MiwidXNlcm5hbWUiOiJuZy1kZW1vIn19
2023-12-09 17:09:08
-23h49m47.29781892s false

Python实现

代码:

import base64

s = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDIxMTI5NDgsImlhdCI6MTcwMjAyNjU0OCwiaXNzIjoid2wiLCJhdXRoRGF0YSI6eyJpZCI6MiwidXNlcm5hbWUiOiJuZy1kZW1vIn19.T1jEV5wzd9g1aCmmP5gFlw_PuPBoGlVVRUSqHJXJ0p4"
sArr = s.split('.')

payload = sArr[1]

print(payload)
payload = payload + '=' * (4 - len(payload) % 4)
print(payload)

r = base64.urlsafe_b64decode(payload + '=' * (4 - len(payload) % 4))
print(r)

输出:

eyJleHAiOjE3MDIxMTI5NDgsImlhdCI6MTcwMjAyNjU0OCwiaXNzIjoid2wiLCJhdXRoRGF0YSI6eyJpZCI6MiwidXNlcm5hbWUiOiJuZy1kZW1vIn19
eyJleHAiOjE3MDIxMTI5NDgsImlhdCI6MTcwMjAyNjU0OCwiaXNzIjoid2wiLCJhdXRoRGF0YSI6eyJpZCI6MiwidXNlcm5hbWUiOiJuZy1kZW1vIn19====
b'{"exp":1702112948,"iat":1702026548,"iss":"wl","authData":{"id":2,"username":"ng-demo"}}'

注意: python和go实现上的区别,当base64字符串正好被4整除时,go仍然添加4个=的后缀,解析会报错: illegal base64 data at input byte 116,在python中没有这个问题。