go - 使用服务帐户在 Golang 中验证对 Cloud Function 的客户端调用

标签 go google-cloud-functions google-oauth

我将自己的云功能部署到 GCP。在云功能上,我启用了使用 Google 服务帐户进行身份验证。我需要编写一个 Golang 代码来调用这个云函数。我用 Nodejs 完成了同样的目的,但不能让 Golang 工作。

这是我的 Nodejs 代码(工作):

const {GoogleAuth} = require('google-auth-library');

const targetAudience = "cloud-function-url"

async function run() {
    const auth = new GoogleAuth();

    const client = await auth.getIdTokenClient(targetAudience);
    const res = await client.request({ url });
    console.info(res.data);
}

我的 Golang 代码:

import  "golang.org/x/oauth2/google"
func getToken() (err error) {
    scope := "https://www.googleapis.com/auth/cloud-platform"
    client, err := google.DefaultClient(context.Background(), scope)
    if err != nil {
        return
    }
    res, err := client.Get("cloud-function-url")
    if err != nil {
        return
    }
    fmt.Println(res)
    return
}

我也尝试自定义代码添加targetAudience ,但它也不起作用

baseUrl := "your-cloudfunction-baseurl"
ctx := context.Background()
targetAudience := baseUrl
credentials, err := google.FindDefaultCredentials(ctx)
if err != nil {
    fmt.Printf("cannot get credentials: %v", err)
    os.Exit(1)
}

tokenSrc, err := google.JWTAccessTokenSourceFromJSON(credentials.JSON, targetAudience)
if err != nil {
    fmt.Printf("cannot create jwt source: %v", err)
    os.Exit(1)
}

client := oauth2.NewClient(context.Background(), tokenSrc)
if err != nil {
    return
}
res, err := client.Get(baseUrl + "sub-url")
if err != nil {
    return
}

我已检查并确保我的服务帐户已正确加载。在上述两种情况下,我都收到了 401 "The access token could not be verified"

最佳答案

一段时间后深入了解 Google's Oauth ProtocolOAuth2 ,我发现 Golang 中的库没有完全遵循 google 的 OAuth2 协议(protocol)。

  • Google 规范中的流程:在 HTTP 客户端(使用服务帐户)中生成和签名 JWT --> 发送到 google 的服务器 --> 获取新的签名 JWT --> 将新 token 用于其他请求
  • Golang lib:生成并签署 JWT --> 将此 token 用于其他请求

  • 令人惊讶的是,Nodejs 库正确处理了流程,而 Golang 库却没有。我将我的调查总结为 blog post .

    对于那些想要简短回答的人,这是我的实现(我将一些部分移到了公共(public)仓库中):

    import (
        "context"
        "fmt"
        "io/ioutil"
        "os"
    
        "github.com/CodeLinkIO/go-cloudfunction-auth/cloudfunction"
    
        "golang.org/x/oauth2/google"
    )
    
    func main() {
        baseUrl := "your-cloudfunction-baseurl"
        ctx := context.Background()
        targetAudience := baseUrl
        credentials, err := google.FindDefaultCredentials(ctx)
        if err != nil {
            fmt.Printf("cannot get credentials: %v", err)
            os.Exit(1)
        }
    
        jwtSource, err := cloudfunction.JWTAccessTokenSourceFromJSON(credentials.JSON, targetAudience)
        if err != nil {
            fmt.Printf("cannot create jwt source: %v", err)
            os.Exit(1)
        }
    
        client := cloudfunction.NewClient(jwtSource)
        res, err := client.Get(baseUrl + "/cloudfunction-sub-page")
        if err != nil {
            fmt.Printf("cannot fetch result: %v", err)
            os.Exit(1)
        }
        defer res.Body.Close()
        body, err := ioutil.ReadAll(res.Body)
        if err != nil {
            fmt.Printf("cannot read response: %v", err)
            os.Exit(1)
        }
        println(string(body))
    }
    
    

    关于go - 使用服务帐户在 Golang 中验证对 Cloud Function 的客户端调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61443073/

    相关文章:

    javascript - 如何在 Vue.js 中向 google OAuth2 进行身份验证?

    javascript - GoogleUser 对象没有 grantOfflineAccess 方法?

    go - 如何运行多个 goroutines 并以相同的运行顺序收集结果

    c - 尝试扩展 golang Pigpio 包装函数 gpioWaveAddGeneric

    go - 如何实现文件系统?

    firebase - 只允许具有特定自定义声明的用户调用 Firebase 函数

    java - 如何使用 Oauth 2 从 Gmail 帐户导入 Gmail 联系人

    go - 如何从 golang 中的 math floor 函数中获取整数结果?

    node.js - 错误 : functions predeploy error: Command terminated with non-zero exit code254

    angular - firebase_app__WEBPACK_IMPORTED_MODULE_5__.app(...).functions 不是函数