node.js - 用于验证 GCP 上 Node 应用程序的 API 请求的 Google 服务帐户

标签 node.js google-app-engine passport.js

我们正在为在 Google 应用引擎上运行的 Node 应用程序构建 API 服务。目前,我已经设置了 Passport 以使用“passport-http-bearer”策略来处理对我们 api 的无浏览器 http 请求。这会从请求的授权 header 中获取一个 token ,并使用它来对其进行身份验证。

我们还在构建一个本地 Python 程序,该程序将向 Google 请求 token ,我们将其发送到 Node 应用程序以进行 API 调用。根据我在网上看到的情况,最好的方法似乎是使用与 GCP 项目关联的服务帐户。不幸的是,我见过的所有教程都使用服务帐户凭据来对 Google API 进行授权调用。我想使用服务帐户凭据对我们应用程序的 API 进行授权调用。我的问题是,我似乎找不到任何代码来从请求中获取不记名 token ,然后检查服务帐户以说“是的,这是从正确的帐户生成的”或“不,应该拒绝此请求” 。任何关于如何弥合这一差距的见解都会非常有帮助。目前我的(最初的,非常糟糕的)承载策略是:

passport.use(new BearerStrategy((token, done) => {
  console.log('Bearer called with token: ', token);
  if (token === '<Fake test token for SO>') {
    console.log(' valid token!');
    return done(null, { name: 'api_service' });
  }
  console.log(' invalid token...');
  return done(null, false);
}));

最佳答案

我们最终使用 https 请求直接发送到 google auth 端点。代码如下:

// Bearer token strategy for headless requests.  This is used to authenticate API calls
passport.use(new BearerStrategy((token, done) => {
  //forming the request to hit the google auth endpoint
  const options = {
    host: 'www.googleapis.com',
    path: `/oauth2/v1/tokeninfo?access_token=${token}`,
    headers: {
      Accept: 'application/json'
    }
  };

  //ask google endpoint if the token has the service account's email
  https.get(options, (res) => {
    res.setEncoding('utf8');
    res.on('data', (chunk) => {
      if (JSON.parse(chunk).email === config.get('SVCACCT_NAME')) {
        //good request from the service account
        return done(null, { name: 'api_service' });
      }

      //not the service account
      return done(null, false);
    });
  }).on('error', (err) => {
    console.log('Got API auth error: ', err.message);
    //error or bad token.  Either way reject it
    return done(err, false);
  });
}));

我们使用 shell 脚本和项目控制台中的服务帐户 json 文件来生成用于测试目的的 token (这不会在 Mac 上运行。我必须使用安装了 jq 的 docker 容器。)。稍后我们会将其翻译为 python:

#!/bin/bash

if [ -z "${1}" ]; then
    PROG=$( basename $0 )
    echo "usage: ${PROG} <JSON account file>"
    exit 1
fi
keyfile="${1}"

client_email=$( jq -r '.client_email' $keyfile )
if [ -z "${client_email}" ]; then
    echo "JSON file does not appear to be valid"
    exit 2
fi

private_key=$( jq '.private_key' $keyfile | tr -d '"' )
if [ -z "${private_key}" ]; then
    echo "JSON file does not appear to be valid"
    exit 3
fi

keyfile=$( mktemp -p . privkeyXXXXX )
echo -e $private_key > $keyfile

now=$( date "+%s" )
later=$( date -d '+30 min' "+%s" )
header=$( echo -n "{\"alg\":\"RS256\",\"typ\":\"JWT\"}" | base64 -w 0 )
claim=$( echo -n "{ \"iss\":\"${client_email}\", \"scope\":\"email profile\", \"aud\":\"https://www.googleapis.com/oauth2/v4/token\", \"exp\":${later}, \"iat\":${now} }" | base64 -w 0 )

data="${header}.${claim}"

sig=$( echo -n $data | openssl dgst -sha256 -sign $keyfile -keyform PEM -binary | base64 -w 0 )

rm -f $keyfile

stuff=$( echo "${header}.${claim}.${sig}" | sed 's!\/!%2F!g' | sed 's/=/%3D/g' | sed 's/\+/%2B/g' )

curl -d "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${stuff}" https://www.googleapis.com/oauth2/v4/token

关于node.js - 用于验证 GCP 上 Node 应用程序的 API 请求的 Google 服务帐户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48431956/

相关文章:

node.js - mongoose .findByIdAndUpdate 和预更新 Hook 的问题

python - 如何使用将服务器链接到在暴露的本地主机上运行的 flask 应用程序

node.js - 类型错误 : done is not a function (nodemailer)

windows - goapp 部署 : has different path then goapp serve on windows?

google-app-engine - gcloud:如何通过cli下载应用程序

node.js - 从 React 组件调用 passport js 函数的正确方法

Javascript 404 资源未找到 NodeJS

google-app-engine - web2py 类似于谷歌应用引擎

javascript - 将 bcrypt 哈希/验证函数转换为异步函数

node.js - 通过我的 REST API 和 Facebook 进行用户身份验证