在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。
goimport ( "github.com/dgrijalva/jwt-go" "github.com/lestrrat-go/jwx/jwk" )
步骤 2: 从URL加载JWK
通常,JWK集合可以通过一个公开的URL获得。您可以使用jwk.Fetch
函数来从URL加载JWK集合。
gourl := "https://example.com/.well-known/jwks.json" set, err := jwk.Fetch(url) if err != nil { // 处理错误 }
步骤 3: 解析JWT并提取其头部
在验证签名之前,需要解析JWT以提取其头部,特别是kid
(Key ID)属性,这对于从JWK集合中选择正确的密钥是必要的。
gotokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // 不验证签名 return nil, nil }) if token == nil { // 处理错误 } // 获取kid kid := token.Header["kid"].(string)
步骤 4: 根据kid选择正确的JWK
使用从JWT头部得到的kid
来从JWK集合中选择正确的密钥。
gokeys := 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的签名。
gotoken, err = jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { return key, nil }) if err != nil { // 处理错误,比如签名不匹配 return } if !token.Valid { // Token无效 return }
完整的例子
将上述步骤整合到一个函数中,可以创建一个验证JWT签名的完整应用。
gofunc 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
的值来针对不同的场景进行测试。
2024年8月16日 00:11 回复