在 Go 中验证 Google 登录 ID 令牌
Posted
技术标签:
【中文标题】在 Go 中验证 Google 登录 ID 令牌【英文标题】:Validating Google sign in ID token in Go 【发布时间】:2016-08-11 11:56:45 【问题描述】:我正在寻找使用 Go 后端服务器项目为 android 的 Google 登录验证 ID 令牌的方法。
在 Go 中使用 Google API 客户端库验证 ID 令牌的等效函数是什么?
从此页面使用 Google API 客户端库部分
https://developers.google.com/identity/sign-in/android/backend-auth#using-a-google-api-client-library
有 Java 和 Python 示例,还有用于验证 ID 令牌的链接,用于使用适用于 php、Node.js 和其他语言的 Google API 客户端库。我检查了我的目标语言;去这里
https://github.com/google/google-api-go-client/blob/master/GettingStarted.md
但是,我发现没有像 Java 和 Python 示例中那样验证令牌的等效函数。 Go 中有什么函数可以做这样的事情吗?
我不想使用令牌信息端点
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123
因为它引入了可能的延迟和网络错误。我希望使用 Google API 客户端库。请指导我应该在哪里查看。
【问题讨论】:
【参考方案1】:这就是我使用 https://github.com/google/google-api-go-client 库的方式:
import (
"google.golang.org/api/oauth2/v2"
"net/http"
)
var httpClient = &http.Client
func verifyIdToken(idToken string) (*oauth2.Tokeninfo, error)
oauth2Service, err := oauth2.New(httpClient)
tokenInfoCall := oauth2Service.Tokeninfo()
tokenInfoCall.IdToken(idToken)
tokenInfo, err := tokenInfoCall.Do()
if err != nil
return nil, err
return tokenInfo, nil
oauth2.Tokeninfo 对象包含有关用户的信息。 请注意,这会调用 https://www.googleapis.com/oauth2/v2/tokeninfo,我认为所有 Google API 客户端库都会在后台进行此 http 调用。
【讨论】:
看来我们需要调用 oauth2/v3 而不是 /v2,如果我们仍然需要调用该 url,如何避免延迟和网络问题? google-api-go-client 没有 oauth2/v3,但 v2 运行良好。不知道能不能避免http调用。oauth2.New(httpClient)
似乎被标记为已弃用以支持oauth2.NewService(ctx, ClientOption)
This issue 建议您实际上应该使用 idtoken 包。【参考方案2】:
Google 的 idToken 实际上是 JWT 格式,是紧凑且自包含的带有签名的 JSON。
另请参阅:https://jwt.io/introduction/
google-auth-library-nodejs 的 OAuth2Client.prototype.verifyIdToken 使用 Google 的公钥验证 idtoken 并从 idtoken 中提取 ClaimSet 而无需调用 tokeninfo 端点。
我刚刚从 google-auth-library-nodejs 移植了 verifyIdToken 函数,并为此创建了一个库:https://github.com/futurenda/google-auth-id-token-verifier。
用法:
import (
"github.com/futurenda/google-auth-id-token-verifier"
)
v := googleAuthIDTokenVerifier.Verifier
aud := "xxxxxx-yyyyyyy.apps.googleusercontent.com"
err := v.VerifyIDToken(TOKEN, []string
aud,
)
if err == nil
claimSet, err := googleAuthIDTokenVerifier.Decode(TOKEN)
// claimSet.Iss,claimSet.Email ... (See claimset.go)
【讨论】:
【参考方案3】:import (
"google.golang.org/api/idtoken"
)
var token string // this comes from your web or mobile app maybe
const googleClientId = "" // from credentials in the Google dev console
tokenValidator, err := idtoken.NewValidator(context.Background())
if err != nil
// handle error, stop execution
payload, err := tokenValidator.Validate(context.Background(), token, googleClientId)
if err != nil
// handle error, stop execution
email := payload.Claims["email"]
name := payload.Claims["name"]
// and so on...
您可能需要向您的应用程序提供您的 Google 凭据: https://cloud.google.com/docs/authentication/production
【讨论】:
在创建 NewValidator 之前,它希望 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为从控制台下载的 json 文件。否则, idtoken.NewValidator 会失败,因为它需要一些凭据。我无法让它与 idtoken.Validate 一起使用。我收到此错误:Get "googleapis.com/oauth2/v3/certs": private key should be a PEM or plain PKCS1 or PKCS8;解析错误:asn1:语法错误:序列被截断。有什么想法吗?【参考方案4】:这很简单,并且有一个单行解决方案。只需使用官方图书馆:
go get google.golang.org/api/idtoken"
然后写下这段代码:
payload, err := idtoken.Validate(context.Background(), request.IdToken, "your google client id")
if err != nil
panic(err)
fmt.Print(payload.Claims)
然后你会得到这个输出:
map[
aud:<Your web application client id>
azp:<Your android application client id>
email:<Authenticated user email>
email_verified:true
exp:<expire at>
family_name:<Authenticated user lastname>
given_name:<Authenticated user firstname>
iat:<issued at>
iss: <accounts.google.com or https://accounts.google.com>
locale:en
name:<Authenticated User fullname>
picture:<Authenticated User Photo URL>
sub: <Google Account ID [Use this to identify a id uniquely]>
]
【讨论】:
我相信这是新的正确答案。 idtoken 在 Python 等其他语言中是 oauth2 的子包,有点令人困惑,但在 Go 中它是一个单独的库以上是关于在 Go 中验证 Google 登录 ID 令牌的主要内容,如果未能解决你的问题,请参考以下文章
用于在 GAE 上运行的 Go 中验证 Google 登录令牌的包
Google 登录 - 访问令牌、身份验证令牌和 JWT ID 令牌之间的区别
使用 Google 登录 - 我们如何在 .net 中验证 Google ID 令牌服务器端?缺少代码示例,库似乎已弃用