我们正在为在 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/