【问题标题】:Connecting to Google API with Service Account and OAuth使用服务帐户和 OAuth 连接到 Google API
【发布时间】:2019-05-26 05:02:14
【问题描述】:

我使用的环境不支持 GCP 客户端库。所以我想弄清楚如何使用手动制作的 JWT 令牌直接进行身份验证。

我已经从这里使用 nodeJS 测试环境调整了任务,用 jwa 来实现算法。

https://developers.google.com/identity/protocols/OAuth2ServiceAccount

私钥取自服务帐户文件的 JSON 版本。

当测试运行时,它会捕获一个非常基本的 400 错误,即“无效请求”。我不知道如何解决它。

有人可以帮忙找出我做错了什么吗?

var assert = require('assert');
const jwa = require('jwa');
const request = require('request-promise');

const pk = require('../auth/tradestate-2-tw').private_key;

const authEndpoint = 'https://www.googleapis.com/oauth2/v4/token';


describe('Connecting to Google API', function() {

    it('should be able to get an auth token for Google Access', async () => {
      assert(pk && pk.length, 'PK exists');
      const header = { alg: "RS256", typ: "JWT" };
      const body = {
        "iss":"salesforce-treasury-wine@tradestate-2.iam.gserviceaccount.com",
        "scope":"https://www.googleapis.com/auth/devstorage.readonly",
        "aud":"https://www.googleapis.com/oauth2/v4/token",
        "exp": new Date().getTime() + 3600 * 1000,
        "iat": new Date().getTime()
      };
      console.log(JSON.stringify(body, null, 2));
      const encodedHeader = Buffer.from(JSON.toString(header)).toString('base64')
      const encodedBody = Buffer.from(JSON.toString(body)).toString('base64');
      const cryptoString = `${encodedHeader}.${encodedBody}`;
      const algo = jwa('RS256');
      const signature = algo.sign(cryptoString, pk);
      const jwt = `${encodedHeader}.${encodedBody}.${signature}`;
      console.log('jwt', jwt);
      const headers = {'Content-Type': 'application/x-www-form-urlencoded'};
      const form = {
        grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        assertion: jwt
      };
      try { 
        const result = await request.post({url: authEndpoint, form, headers});
        assert(result, 'Reached result');
        console.log('Got result', JSON.stringify(result, null, 2));
      } catch (err) {
        console.log(JSON.stringify(err, null, 2));
        throw (err);
      }

    });
});

【问题讨论】:

  • 我写了一篇文章,详细介绍了所涉及的步骤。这包括 Python 中的真实源代码,以向您展示这些步骤。解释了重要的主要步骤,如何创建 JWT 以及如何将 JWT 交换为令牌。 jhanley.com/…
  • 我要做的另一件事是让 iat 和 exp 使用相同的新 Date() 对象,而不是调用两次。
  • 嗨@abelito 我已经尝试过了,但是根据您的回答,它会导致错误。但是对 JSON.stringify 的更改效果很好。但是现在我有另一个关于 iad 和到期时间的问题......可能是时区吗?

标签: google-cloud-platform google-iam


【解决方案1】:

使用 JSON.stringify 而不是 JSON.toString。从您问题中的链接:

{"alg":"RS256","typ":"JWT"}

这个的Base64url表示如下:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

当使用 JSON.toString() 和 base64 编码时,您会得到 W29iamVjdCBKU09OXQ== 这解释了无效请求的 400,因为它无法解密您发送的任何内容。

【讨论】:

  • 哦,太好了,这真是一种解脱。我正睁着眼睛试图找出问题所在。我对新错误更进一步:' StatusCodeError: 400 - "{\n \"error\": \"invalid_grant\",\n \"error_description\": \"Invalid JWT: Token must be a短期令牌(60 分钟)并在合理的时间范围内。检查您的 iat 和 exp 值,并使用带有偏差的时钟来解决系统之间的时钟差异。\"\n}"'
  • 这是我根据之前评论更改的代码: const now = new Date().getTime();常量然后 = 现在 + 3600 * 1000; const body = { "iss":"salesforce-treasury-wine@tradestate-2.iam.gserviceaccount.com", "scope":"googleapis.com/auth/devstorage.readonly", "aud":"googleapis.com/oauth2/v4/token", "exp":然后,“iat”:现在 };
  • 我很高兴 stringify 有帮助!我正在考虑你的新问题,但现在尝试更短的时间......也许 15 或 30 分钟?可能是您在上述评论中提到的 UTC 与本地时区问题
  • @RichardG stackoverflow.com/questions/36189612/… 看起来您发出请求的计算机/服务器的系统时钟可能与 NTP 不同步
  • 啊终于明白了! iat 和 exp 中的日期以“秒”而不是毫秒为单位。所以我需要转换它:const now = Date().getTime() / 1000。感谢您的帮助,我现在将其标记为正确。
猜你喜欢
  • 2018-01-11
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 2013-05-25
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 2020-09-06
相关资源
最近更新 更多