使用服务帐户对Golang中的Cloud Function的客户端调用进行身份验证

时间:2020-04-26 15:10:16

标签: go google-cloud-functions google-oauth

我将自己的云功能部署到了GCP。在云功能上,我启用了使用Google服务帐户进行身份验证的功能。我需要编写Golang代码来调用此云函数。我已经用Node.js达到了相同的目的,但是无法使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"

2 个答案:

答案 0 :(得分:1)

在深入研究Google's Oauth ProtocolOAuth2之后,我发现Golang中的库未完全遵循Google的OAuth2协议。

  • 按照Google的规范进行操作:在HTTP客户端中生成并签名JWT(使用服务帐户)->发送至Google的服务器->获取新的签名JWT->将新令牌用于其他请求
  • Golang库:生成并签名JWT->使用此令牌处理其他请求

令人惊讶的是,Nodejs库能够正确处理流,而Golang却不能。我将调查总结为blog post

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

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))
}

答案 1 :(得分:0)

我写了一个名为token-generator的开源应用。它在Go中,并且我生成了签名身份令牌,以便能够调用私有Cloud Run和Cloud Function。

随意使用它或复制您自己的应用程序所需的核心代码!!我们可以在这里讨论,或者根据需要在GitHub上发布问题。

相关问题