Node.js Can';t使用代理对googleapis进行JWT身份验证

Node.js Can';t使用代理对googleapis进行JWT身份验证,node.js,proxy,google-api,google-api-nodejs-client,Node.js,Proxy,Google Api,Google Api Nodejs Client,我有一个NodeJS API在一个公司代理的背后工作,我一直在尝试使用谷歌的NodeJS客户端进行身份验证: const google = require('googleapis'); function getServiceAccountInfo() { return { type: 'service_account', project_id: 'XXXXX', private_key_id: 'XXXXXX', private_key: 'XXXX',

我有一个NodeJS API在一个公司代理的背后工作,我一直在尝试使用谷歌的NodeJS客户端进行身份验证:

const google = require('googleapis');

function getServiceAccountInfo() {
  return {
    type: 'service_account',
    project_id: 'XXXXX',
    private_key_id: 'XXXXXX',
    private_key: 'XXXX',
    client_email: 'XXXX',
    client_id: 'XXXX',
    auth_uri: 'XXXX',
    token_uri: 'XXXX',
    auth_provider_x509_cert_url: 'XXXX',
    client_x509_cert_url: 'XXXXX'
  };
}

const SCOPES = 'https://www.googleapis.com/auth/firebase.messaging';

let proxy2 = {
  host: 'proxy.hkcsl.net',
  port: 8080
};

const proxy3 = {
  proxy: 'http://172.25.2.6:8080'
}

const proxy4 = {
  proxy: {
    host: '172.25.2.6',
    port: 8080,
    auth: {
      username: '',
      password: '',
    },
  }
}

process.env.HTTPS_PROXY = 'https://172.25.2.6:8080';
process.env.https_proxy = 'https://172.25.2.6:8080';
process.env.HTTP_PROXY = 'http://172.25.2.6:8080';
process.env.http_proxy = 'http://172.25.2.6:8080';
google.options({
  proxy: proxy4.proxy
});

const key = getServiceAccountInfo();
const jwtClient = new google.auth.JWT(
  key.client_email,
  undefined, // null,
  key.private_key,
  SCOPES,
  undefined, // null
);
jwtClient.authorize(function(err, tokens) {
  if (err) {
    console.error(err);
    return;
  }
  console.log(tokens.access_token);
});
但是,无论我如何配置代理选项,我仍然会收到超时错误或类似错误

错误:write EPROTO 101057795:错误:140770FC:SSL例程:SSL23\u GET\u SERVER\u HELLO:未知协议:openssl\SSL\s23\u clnt.c:827:

有些人通过将端口更改为443来修复它,但它不适用于我的情况,因为我在服务器内部无法使用该端口。我已经提到了这里提出的讨论和解决方案:


Vue昨天似乎也遇到了类似的问题,他们从使用axios改为使用request。GoogleAppis也有类似的解决方案吗?

在参考了关于with axios的解决方案后,
GoogleAPI nodejs客户端(即
GoogleAppis
)正在使用,并在
GoogleAuth库nodejs
()和
节点gtoken
()的源代码中爬行,我编写了以下方法来手动从Google请求令牌,作为临时解决方法:

const axios = require('axios-https-proxy-fix');
const querystring = require('querystring');
const jws = require('jws');

const GOOGLE_TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
const GOOGLE_REVOKE_TOKEN_URL =
    'https://accounts.google.com/o/oauth2/revoke?token=';

const SCOPES = 'https://www.googleapis.com/auth/firebase.messaging';

const PROXY = {
  host: '172.25.2.6',
  port: 8080,
  auth: {
    username: '',
    password: '',
  }
};

function getServiceAccountInfo() {
  return {
    type: 'service_account',
    project_id: 'XXXX',
    private_key_id: 'XXXX',
    private_key: 'XXXX',
    client_email: 'XXXX',
    client_id: 'XXXX',
    auth_uri: 'https://accounts.google.com/o/oauth2/auth',
    token_uri: 'https://accounts.google.com/o/oauth2/token',
    auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
    client_x509_cert_url: 'XXXX'
  };
}

function requestToken(client_email, private_key) {
  const iat = Math.floor(new Date().getTime() / 1000);
  const additionalClaims = {};
  const payload = Object.assign(
    {
      iss: client_email,
      scope: SCOPES,
      aud: GOOGLE_TOKEN_URL,
      exp: iat + 3600,
      iat,
      sub: undefined
    },
    additionalClaims);
  const signedJWT =
    jws.sign({header: {alg: 'RS256'}, payload, secret: private_key});
  return axios({
    method: 'post',
    url: GOOGLE_TOKEN_URL,
    data: querystring.stringify({
      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      assertion: signedJWT
    }),
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    proxy: PROXY
  })
  .then(r => {
    const body = r.data;
    console.log(body);
    return body.access_token;
  })
  .catch(e => {
    const body = (e.response && e.response.data) ? e.response.data : {};
    let err = e;
    if (body.error) {
      const desc =
          body.error_description ? `: ${body.error_description}` : '';
      err = new Error(`${body.error}${desc}`);
    }
    throw err;
  });
}

const key = getServiceAccountInfo();
requestToken(key.client_email, key.private_key);

参考资料:

我(在macOS上)偶然发现的最佳解决方案是将
proxychain4
与以下配置一起使用

strict_chain

tcp_read_time_out 15000
tcp_connect_time_out 8000

localnet 127.0.0.0/255.0.0.0

[ProxyList]
http {your proxy ip address} {your proxy port}


哦,伙计,从2020年起,这个问题就不会在本地解决了。。