【问题标题】:Unable to access Google Spreadsheets with a service account credentials using Golang无法使用 Golang 使用服务帐户凭据访问 Google 电子表格
【发布时间】:2019-11-15 09:56:48
【问题描述】:

我正在编写一个 AWS Lambda 代码,用于使用 Golang 访问和更新将 URL 作为输入的电子表格。到目前为止,我可以按照 Google 指南使用 OAuth 客户端 ID 在本地访问电子表格 - https://developers.google.com/sheets/api/quickstart/go

但由于我想从 AWS Lambda 运行代码,我想使用 Google 服务帐户执行身份验证。我创建了一个服务帐户并收到了包含以下信息的凭据。

{
"type": "service_account",
"project_id": "quickstart-1XXXXXXX806",
"private_key_id": "a1XXXXXXXXXXXXXXXXXXXXX3c3e5d8e",
"private_key": "-----BEGIN PRIVATE KEY-----\nMZ4C8......\nD\n-----END PRIVATE KEY-----\n",
"client_email": "lambda@quickstart-1XXXXXXX806.iam.gserviceaccount.com",
"client_id": "1XXXXXXXXXXXXXXXXX2",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lambda%40quickstart-1573627656806.iam.gserviceaccount.com"

}

我阅读了很多文档,但没有找到任何关于使用 Google 服务帐户使用 Golang 代码访问 Google 电子表格的参考资料。每个文档参考以下 Github 链接 - https://github.com/googleapis/google-api-go-client 但是由于我最近开始在 Golang 中工作,我真的不明白如何实现它。阅读 Google 指南后,我了解服务帐户所需的流程如下 -

但我仍然无法为此编写 Golang 代码。如果有人可以分享一些参考资料,我将不胜感激:)

【问题讨论】:

    标签: authentication go google-api google-oauth google-sheets-api


    【解决方案1】:

    @ZektorH 的回答帮助我完成了这段代码。下面是使用服务帐户从 Google 电子表格中提取数据的完整工作示例。

    package main
    
    import (
        "fmt"
        "log"
    
        "golang.org/x/oauth2"
        "golang.org/x/oauth2/jwt"
        "google.golang.org/api/sheets/v4"
    )
    
    
    func main() {
    
        // Create a JWT configurations object for the Google service account
        conf := &jwt.Config{
            Email:        "lambda@quickstart-XXXXXXXXXX.iam.gserviceaccount.com",
            PrivateKey:   []byte("-----BEGIN PRIVATE KEY-----\nxxxxxx\n-----END PRIVATE KEY-----\n"),
            PrivateKeyID: "a1a6xxxxxxxxxxxxxxxxxxxxxxxe5d8e",
            TokenURL:     "https://oauth2.googleapis.com/token",
            Scopes: []string{
                "https://www.googleapis.com/auth/spreadsheets.readonly",
            },
        }
    
        client := conf.Client(oauth2.NoContext)
    
        // Create a service object for Google sheets
        srv, err := sheets.New(client)
        if err != nil {
            log.Fatalf("Unable to retrieve Sheets client: %v", err)
        }
    
        // Change the Spreadsheet Id with yours    
        spreadsheetId := "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
    
        // Define the Sheet Name and fields to select
        readRange := "Sheet1!A2:B"
    
        // Pull the data from the sheet
        resp, err := srv.Spreadsheets.Values.Get(spreadsheetId, readRange).Do()
        if err != nil {
            log.Fatalf("Unable to retrieve data from sheet: %v", err)
        }
    
        // Display pulled data
        if len(resp.Values) == 0 {
            fmt.Println("No data found.")
        } else {
            fmt.Println("Name, Major:")
            for _, row := range resp.Values {
                fmt.Printf("%s, %s\n", row[0], row[1])
            }
        }
    }
    

    另外,请注意,如果您收到如下错误:

    googleapi: 错误 403: 调用者没有权限,禁止

    那么您可能没有授予您的 Google 帐户访问该电子表格的权限。如果是这样-

    • 只需在浏览器中转到您要与之交互的 Google 表格即可。

    • 转到屏幕右上角的 SHARE。

    • 转到高级设置并与您的服务帐户前的电子邮件地址共享。 lambda@quickstart-XXXXXXXXXX.iam.gserviceaccount.com

    【讨论】:

    • 感谢您提供有关如何解决权限问题的提示,这真的让我抓狂。此外,还有一种更好的方法来初始化这里提到的凭据*.com/questions/39691100/…
    【解决方案2】:

    经过一番挖掘,我发现了一些 documentation,它解释了如何在 Golang 上使用服务帐户。在文档中有一个example 说明如何使用服务帐户执行身份验证:

    // Your credentials should be obtained from the Google
    // Developer Console (https://console.developers.google.com).
    conf := &jwt.Config{
        Email: "xxx@developer.gserviceaccount.com",
        // The contents of your RSA private key or your PEM file
        // that contains a private key.
        // If you have a p12 file instead, you
        // can use `openssl` to export the private key into a pem file.
        //
        //    $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
        //
        // The field only supports PEM containers with no passphrase.
        // The openssl command will convert p12 keys to passphrase-less PEM containers.
        PrivateKey: []byte("-----BEGIN RSA PRIVATE KEY-----..."),
        Scopes: []string{
            "https://www.googleapis.com/auth/bigquery",
            "https://www.googleapis.com/auth/blogger",
        },
        TokenURL: google.JWTTokenURL,
        // If you would like to impersonate a user, you can
        // create a transport with a subject. The following GET
        // request will be made on the behalf of user@example.com.
        // Optional.
        Subject: "user@example.com",
    }
    // Initiate an http.Client, the following GET request will be
    // authorized and authenticated on the behalf of user@example.com.
    client := conf.Client(oauth2.NoContext)
    client.Get("...")
    

    【讨论】:

    • 感谢@ZektorH 分享示例和链接。更改 Scopes 参数后,它对我有用。你真的救了我的命。