How to verify JWT signature with JWK in Go?
在Go语言中,使用JWK(JSON Web Keys)来验证JWT(JSON Web Tokens)的签名是一个涉及几个步骤的过程。以下是详细的步骤和示例,说明如何在Go中实现这一功能。步骤 1: 导入必要的包首先,您需要导入处理JWT和JWK所需的包。github.com/dgrijalva/jwt-go是处理JWT的流行库,而github.com/lestrrat-go/jwx库可以用来处理JWK。import ( "github.com/dgrijalva/jwt-go" "github.com/lestrrat-go/jwx/jwk")步骤 2: 从URL加载JWK通常,JWK集合可以通过一个公开的URL获得。您可以使用jwk.Fetch函数来从URL加载JWK集合。url := "https://example.com/.well-known/jwks.json"set, err := jwk.Fetch(url)if err != nil { // 处理错误}步骤 3: 解析JWT并提取其头部在验证签名之前,需要解析JWT以提取其头部,特别是kid(Key ID)属性,这对于从JWK集合中选择正确的密钥是必要的。tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // 不验证签名 return nil, nil})if token == nil { // 处理错误}// 获取kidkid := token.Header["kid"].(string)步骤 4: 根据kid选择正确的JWK使用从JWT头部得到的kid来从JWK集合中选择正确的密钥。keys := set.LookupKeyID(kid)if len(keys) == 0 { // 处理错误,没有找到对应的key return}var key interface{}if err := keys[0].Raw(&key); err != nil { // 处理错误 return}步骤 5: 验证JWT签名最后,使用从JWK集合中得到的密钥来验证JWT的签名。token, err = jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { return key, nil})if err != nil { // 处理错误,比如签名不匹配 return}if !token.Valid { // Token无效 return}完整的例子将上述步骤整合到一个函数中,可以创建一个验证JWT签名的完整应用。func verifyJWT(tokenString string, jwksUrl string) (bool, error) { set, err := jwk.Fetch(jwksUrl) if err != nil { return false, err } token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { kid := token.Header["kid"].(string) keys := set.LookupKeyID(kid) if len(keys) == 0 { return nil, fmt.Errorf("no key found for kid: %s", kid) } var key interface{} if err := keys[0].Raw(&key); err != nil { return nil, err } return key, nil }) if err != nil { return false, err } return token.Valid, nil}这个函数封装了从JWK集合中加载密钥、解析JWT、验证签名等过程。您可以通过改变tokenString和jwksUrl的值来针对不同的场景进行测试。