如何在 go 中解析从 google OAuth 2.0 返回的 JWT 令牌?

问题描述 投票:0回答:1

我正在取回有效的:

https://developers.google.com/identity/gsi/web/reference/js-reference#CredentialResponse

按照以下步骤操作后:

https://developers.google.com/identity/gsi/web/guides/migration

即这一切都有效:

    <script src="https://accounts.google.com/gsi/client" async defer></script>
    <div id="g_id_onload"
         data-client_id="YOUR_CLIENT_ID"
         data-callback="handleCredentialResponse">
    </div>
    <div class="g_id_signin" data-type="standard"></div>

并且我使用有效的 CredentialResponse base64 编码的 JWT 来调用

handleCredentialResponse

function handleCredentialResponse(googleUser) {
  console.log(googleUser);
  var token = googleUser.credential;
  sendDataToRoute('/google/login', token); 
}

我可以在 go 的后端执行此操作:

  tokens := strings.Split(token, ".")
  base64Url := tokens[1]
  decoded, _ := base64.StdEncoding.DecodeString(base64Url)
  jsonString := string(decoded) + "}"

我会得到一些不错的 json,其中包含用户的姓名和电子邮件,但 json 缺少最后的结束语

}

当我尝试使用时:

func parseJwt(tokenString string) {
  secret := os.Getenv("GOOGLE_SECRET")

  token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
    }
    return []byte(secret), nil
  })

  if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
    fmt.Println(claims["email"], claims)
  } else {
    fmt.Println(err)
  }
}

它总是因无效的 JWT 错误而出现恐慌。我尝试过在

parseJwt
逻辑之前和之后、base64 之前和之后使用令牌调用
strings.Split(".")[1]
,但似乎没有任何东西可以解析它。

我上面的代码在生产中添加了结尾

}
并且它正在“工作”,但它并没有真正检查秘密以确保 jwt 有效。我该如何解决这个问题?

go google-api jwt google-oauth google-signin
1个回答
0
投票

好的找到答案了!它与您所做的oauth cred SECRET 无关。您使用公共谷歌密钥进行验证:

https://www.googleapis.com/oauth2/v3/certs

来自:

The ID token is properly signed by Google. Use Googles
public keys (available in JWK or PEM format) to verify
the tokens signature. These keys are regularly rotated;
examine the Cache-Control header in the response to
determine when you should retrieve them again.

上面是 JWK 格式,您应该点击该 url 并在 Cache-Control 标头中定义的一段时间内缓存 json。

然后这是使用这些密钥来验证 jwt 的工作示例:

https://github.com/MicahParks/keyfunc/blob/master/examples/json/main.go

import (
  "encoding/json"
  "log"
  "github.com/golang-jwt/jwt/v5"
  "github.com/MicahParks/keyfunc/v2"
)

jwksJSON := json.RawMessage(thatJson)
jwks, _ := keyfunc.NewJSON(jwksJSON)
token, _ := jwt.Parse(yourJwtFromGoogle, jwks.Keyfunc)
return token.Valid

这是将该 json 缓存 24 小时的逻辑:

func writeGoogleFile(file string) string {
  // https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
  // cache-control: public, max-age=18702, must-revalidate, no-transform
  jsonString, code := network.GetTo("https://www.googleapis.com/oauth2/v3/certs", "")
  if code == 200 {
    ioutil.WriteFile(file, []byte(jsonString), 0644)
    return jsonString
  }
  return ""
}
func getGoogleCerts() string {
  file := "/certs/google_jwt_oauth.json"
  fileInfo, err := os.Stat(file)
  if err != nil {
    return writeGoogleFile(file)
  }
  lastModified := fileInfo.ModTime().Unix()
  if time.Now().Unix()-lastModified > 86400 {
    return writeGoogleFile(file)
  }
  b, _ := ioutil.ReadFile(file)
  return string(b)
}
© www.soinside.com 2019 - 2024. All rights reserved.