Google服务帐户,用于验证对GCP上的节点应用程序的API请求

时间:2018-01-24 21:33:24

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

我们正在为在Google应用引擎上运行的节点应用构建api服务。目前,我已设置护照以使用'passport-http-bearer'策略来处理对我们的api的无浏览器http请求。这将从请求的授权标头中获取令牌,并使用该令牌对其进行身份验证。

我们还在构建一个本地python程序,该程序将请求Google提供令牌,我们将发送给节点应用程序以进行API调用。基于我在网络上看到的内容,似乎最好的方法是使用与GCP项目相关联的服务帐户。不幸的是,我见过的所有教程都使用服务帐户凭据来对Google API进行授权调用。我想使用服务帐户凭据对我们的应用程序API进行授权调用。我的问题是,我似乎无法找到任何代码从请求中获取持有者令牌,然后检查服务帐户是否说“是这是从正确的帐户生成”或“不应该拒绝此请求” 。任何有关如何弥合这一差距的见解都会非常有帮助。目前我的(最初的,非常差的)承载策略是:

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);
}));

2 个答案:

答案 0 :(得分:1)

我们最终直接向google auth端点使用https请求。这是代码:

// 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文件来生成用于测试目的的令牌(这不会在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

答案 1 :(得分:0)

Google提供了google.oauth2.id_token模块来帮助验证令牌。

verify_oauth2_token已用于检查Google令牌:

verify_oauth2_token(id_token, request, audience=None)[source]
    Verifies an ID Token issued by Google’s OAuth 2.0 authorization server.
[ ... ] 
    Returns:  The decoded token.