使用 jwt 调用 google api 以对原始端点进行服务到服务调用的工作节点示例?

Posted

技术标签:

【中文标题】使用 jwt 调用 google api 以对原始端点进行服务到服务调用的工作节点示例?【英文标题】:Working node example of calling google api with jwt for service-to-service call to raw endpoint? 【发布时间】:2019-03-23 09:27:39 【问题描述】:

我一直在尝试调用jobs.Insert bigquery rest api 端点和节点(jobs.Insert 方法似乎没有在bigquery 节点库中公开)。

我已经设置了服务到服务的东西,这样我就可以成功调用 bigquery 节点库具有的方法(创建包含私钥等的 json 文件以进行服务到服务)服务调用)。

据我所知,我应该能够使用签名的 jwt 作为承载令牌直接调用其余 api,而无需经过两步 OAuth 过程。

我有东西可以签署 jwt,但仍然遇到身份验证错误,尝试通过 curl (作为第一步)调用原始 api,例如

curl -H "Authorization: Bearer my_signed_jwt" https://www.googleapis.com/bigquery/v2/projects/my_project_id/datasets

("请求具有无效的身份验证凭据。需要 OAuth 2 访问令牌、登录 cookie 或其他有效的身份验证凭据。"

有人有这样做的例子吗?可能只是缺少一个简单的东西,一个工作示例会很明显。

谢谢

【问题讨论】:

由于 Google 有 2 个主要客户端库,因此了解您使用的是哪一个非常重要,请在其中一个包上查看此问题 ***.com/q/54815207/1031958。如果你正在使用它,你需要一个服务帐户,如果你想要 ouath2,你需要使用 Googleapi。 嗨@TamirKlein 谢谢 - 我会再做一遍,特别是关于我使用服务帐户的不同库,看起来应该可以使用签名的 jwt 作为在这种情况下,access_token 直接用于 bigquery 其余端点,而无需先调用 outh2 端点来获取 access_token。也许我的 jwt 很糟糕,我需要确保它里面有正确的东西。顺便说一句,您能否解决您的问题? fyi 我向 bigquery 添加了一个功能请求,以将 jobs.insert 添加到 bigquery api (issuetracker.google.com/issues/129168463) 并且它已经分配。希望从中获得更多有关它的信息。 【参考方案1】:

您可以使用这个工作示例

    初始化query对象 初始化oAuth2对象 致电bigQuery.Jobs.insert

if (!global._babelPolyfill) 
    var a = require("babel-polyfill")


import google from 'googleapis'

let bigQuery = google.bigquery("v2")

describe('Check API', async () => 

    it('Test query', async () => 
        let result = await test('panada')

    )

    async function test(p1) 
        try 
            let query = `SELECT url FROM \`publicdata.samples.github_nested\`
                WHERE repository.owner = 'panada'`

            let auth = getBasicAuthObj()
            auth.setCredentials(
                access_token: "myAccessToken",
                refresh_token: "myRefreshToken"
            )

            let request = 
                "projectId": "myProject",
                auth,
                "resource": 
                    "projectId": "myProject",
                    "configuration": 
                        "query": 
                            query,
                            "useLegacySql": false
                        ,
                        "dryRun": false
                    
                
            

            console.log(`query is: $query`)

            let result = await callBQ(request) //Check JOB status to make sure it's done
            console.log(`result is: $JSON.stringify(result.data)`)

            result.forEach((row, index) => 
                console.log(`row number $index, url is: $row.url`)
            )
         catch (err) 
            console.log("err", err)
        
    

    /**
     * Call BigQuery jobs.insert
     * @param request
     * @returns Promise
     */
    async function callBQ(request) 
        debugger
        console.log("request", request)
        try 
            let result = await bigQuery.jobs.insert(request, request)//, (err, results) => 
            console.log(`All good.....`)

            return result
         catch (e) 
            console.log(`Failed to run query: $e`)
        

    


    /**
     * Create oAuth object
     * @returns OAuth2Client
     */
    function getBasicAuthObj() 
        let clientId = 'myClientId'
        let clientSecret = 'mySecret'
        let redirectUrl = 'url'

        return new google.auth.OAuth2(
            clientId,
            clientSecret,
            redirectUrl
        )
    
)

注意:您需要将此行添加到您的package.json

"googleapis": "34.0.0"

【讨论】:

嘿,谢谢@TamirKlein - 获取访问令牌和刷新令牌是我想要做的两个主要事情,我还没有澄清(通过节点运行,而不是在网络浏览器中运行) - 你是建议在您的示例中在 google 控制台中配置回调 url?我还(在某处)读到,您可以使用签名的 jwt 而无需经过该过程。关于如何为 api 调用获取适当的访问和刷新令牌,我已经看到了许多尚未在我脑海中具体具体化的方法,这对我来说目前是关键的缺失部分。 好的 - 我能够通过类似这样的方式使用 jwt 获取访问令牌和刷新令牌(抱歉格式化,无法输入换行符): const JWT = require('google-授权库'); var jwt = new JWT(jsonObjectFromGoogleKeyEtcFile.client_email, null, jsonObjectFromGoogleKeyEtcFile.private_key, scopes); jwt.authorize(function (err, result) callbackWithErrAndResult(err, result.access_token, result.refresh_token); );【参考方案2】:

好的 - 关于我最初的问题的技巧与获取用于 api 调用的访问令牌有关。

const  JWT  = require('google-auth-library');
function getJWTResultWithAccessAndRefreshToken(jsonObjectFromGoogleKeyEtcFile,
                                                callbackWithErrAndResult) 

var scopes = [
              "https://www.googleapis.com/auth/bigquery",
              "https://www.googleapis.com/auth/cloud-platform",
              "https://www.googleapis.com/auth/devstorage.full_control",
              "https://www.googleapis.com/auth/devstorage.read_only",
              "https://www.googleapis.com/auth/devstorage.read_write"
            ];

var jwt = new JWT(
    jsonObjectFromGoogleKeyEtcFile.client_email,
    null,
    jsonObjectFromGoogleKeyEtcFile.private_key,
    scopes);

jwt.authorize(function (err, result) 
    callbackWithErrAndResult(err, result.access_token, result.refresh_token);
);

这里,jsonObjectFromGoogleKeyEtcFile 是您在 Google Cloud Platform APIs & Services 页面中生成“服务帐户密钥”/Credentials 时获得的 json 文件中的 json 对象。

生成的 access_token 可用于进行如下调用 - 有效 - 我使用了上面函数中的 access_token,并从 jsonObjectFromGoogleKeyEtcFile 的 project_id 属性中获取了 projectId:

curl -H "Authorization: Bearer generated_via_jwt_access_token" \                    
          https://www.googleapis.com/bigquery/v2/projects/projectId/datasets

有趣的是,你也得到了一个 refresh_token,但它的值是“jwt-placeholder”

哇哦。

【讨论】:

以上是关于使用 jwt 调用 google api 以对原始端点进行服务到服务调用的工作节点示例?的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 Google Drive API 的错误 JWT 签名

尝试连接到 Google Oauth for google API 时 JWT 无效

无效签名 - Google JWT API

用于向 Google API (Swift) 验证服务帐户的 JWT 签名无效

如何在 Flutter 的 google_sign_in 中获取 JWT 格式的访问令牌?

JWT 令牌刷新后返回重新调用