我正在尝试设置我网站的分析仪表板,以便我查看网站使用情况。我不希望他们拥有谷歌帐户或单独添加它们以查看结果。
我已经设置了服务帐户和OAuth2访问权限。我找到的所有教程都显示如下代码:
gapi.analytics.auth.authorize({
clientid: 'Service account client ID',
serverAuth: {
access_token: 'XXXXXXXXXXXXXXXXX'
}
所有文档都谈到“......一旦你收到你的访问令牌......”但他们中没有一个人真正说出如何获得它!我看到证书指纹,公钥指纹。我还看到了如何生成JSON和P12键。我不知道如何生成访问令牌。
有人可以解释一下如何做到这一点吗?
我找到了this。它解释说我需要密钥文件并且这是一个坏主意,但没有说明如何实际执行。
我还找到了this。但我对Node.js一无所知,我希望这只是一条可能的路线?
答案 0 :(得分:22)
终于搞定了!使用kjur的jsjws纯JWT的JavaScript实现。我使用this demo作为生成JWT以请求令牌的基础。以下是步骤
在Google Developers控制台中,我创建了一个服务帐户。这是
的说明在Google API控制台中,我将服务帐户添加到凭据中。然后我生成了一个新的JSON密钥。这为我提供了纯文本格式的私钥。
然后我按照谷歌的说明使用HTTP / REST进行授权的API调用。
这是必需的标题信息。
var pHeader = {"alg":"RS256","typ":"JWT"}
var sHeader = JSON.stringify(pHeader);
声明集是这样的。 (这是使用由上述KJUR JWT库提供的语法。)
var pClaim = {};
pClaim.aud = "https://www.googleapis.com/oauth2/v3/token";
pClaim.scope = "https://www.googleapis.com/auth/analytics.readonly";
pClaim.iss = "<serviceAccountEmail@developer.gserviceaccount.com";
pClaim.exp = KJUR.jws.IntDate.get("now + 1hour");
pClaim.iat = KJUR.jws.IntDate.get("now");
var sClaim = JSON.stringify(pClaim);
有争议的一点是将我的私钥放入客户端代码中。对于这种用法,它并不是那么糟糕(我不这么认为。)首先,该网站是我们公司防火墙的后面,所以谁会去&#34; hack&#34;它?其次,即使有人确实得到了它,服务帐户的唯一授权就是查看我们的分析数据 - 我的信息中心的目的是访问该页面的任何人都可以查看我们的分析数据。不打算在这里发布私钥,但基本上就是这样。
var key = "-----BEGIN PRIVATE KEY-----\nMIIC....\n-----END PRIVATE KEY-----\n";`enter code here`
然后使用
生成签名的JWT var sJWS = KJUR.jws.JWS.sign(null, sHeader, sClaim, key);
之后我使用XMLHttpRequest来调用google API。我尝试将FormData与请求一起使用但是没有用。所以老(呃)学校
var XHR = new XMLHttpRequest();
var urlEncodedData = "";
var urlEncodedDataPairs = [];
urlEncodedDataPairs.push(encodeURIComponent("grant_type") + '=' + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer"));
urlEncodedDataPairs.push(encodeURIComponent("assertion") + '=' + encodeURIComponent(sJWS));
urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');
// We define what will happen if the data are successfully sent
XHR.addEventListener('load', function(event) {
var response = JSON.parse(XHR.responseText);
token = response["access_token"]
});
// We define what will happen in case of error
XHR.addEventListener('error', function(event) {
console.log('Oops! Something went wrong.');
});
XHR.open('POST', 'https://www.googleapis.com/oauth2/v3/token');
XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
XHR.send(urlEncodedData)
之后我获得了访问令牌,我可以关注these tutorials使用嵌入API,但授权如下:
gapi.analytics.auth.authorize({
serverAuth: {
access_token: token
}
});
请勿忘记,您必须授予服务帐户查看内容的权限,就像其他任何用户一样。当然,如果服务帐户被授权执行除只读之外的任何操作,那将是一个非常糟糕的主意。
我可能会遇到关于时间和令牌过期的问题,但到目前为止还是如此。
答案 1 :(得分:4)
您可以使用官方(和alpha)Google API for Node.js生成令牌。如果您有服务帐户,这会很有帮助。
在服务器上:
npm install -S googleapis
ES6:
import google from 'googleapis'
import googleServiceAccountKey from '/path/to/private/google-service-account-private-key.json' // see docs on how to generate a service account
const googleJWTClient = new google.auth.JWT(
googleServiceAccountKey.client_email,
null,
googleServiceAccountKey.private_key,
['https://www.googleapis.com/auth/analytics.readonly'], // You may need to specify scopes other than analytics
null,
)
googleJWTClient.authorize((error, access_token) => {
if (error) {
return console.error("Couldn't get access token", e)
}
// ... access_token ready to use to fetch data and return to client
// even serve access_token back to client for use in `gapi.analytics.auth.authorize`
})
答案 2 :(得分:1)
现在,服务帐户身份验证有一个 getAccessToken
方法可以为我们执行此操作。
const {google} = require('googleapis');
const main = async function() {
const auth = new google.auth.GoogleAuth({
keyFile: __dirname + '/service-account-key.json',
scopes: [ 'https://www.googleapis.com/auth/cloud-platform']
});
const accessToken = await auth.getAccessToken()
console.log(JSON.stringify(auth, null, 4))
console.log(JSON.stringify(accessToken, null, 4));
}
main().then().catch(err => console.log(err));
答案 3 :(得分:0)
你有(下面)没有单引号
gapi.analytics.auth.authorize({
serverAuth: {
access_token: token
}
});
但要使其正常工作,根据他们的文档,您需要在serverAuth
和access_token
周围加上单引号。
gapi.analytics.auth.authorize({
'serverAuth': {
'access_token': token
}
});
答案 4 :(得分:0)
我在寻找类似的东西时遇到了这个问题,并认为我会分享一个我最终得到的 node.js 解决方案。本质上,我将一个 google 服务帐户保存到 sa.json 文件中,然后用它来签署我发送给 gcp 的 jwt。
const jwt = require("jsonwebtoken");
const sa = require("./sa.json");
const fetch = require("isomorphic-fetch");
const authUrl = "https://www.googleapis.com/oauth2/v4/token";
const scope = "https://www.googleapis.com/auth/cloud-platform";
const getSignedJwt = () => {
const token = {
iss: sa.client_email,
iat: parseInt(Date.now() / 1000),
exp: parseInt(Date.now() / 1000) + 60 * 60, // 60 minutes
aud: authUrl,
scope,
};
return jwt.sign(token, sa.private_key, { algorithm: "RS256" });
};
const getGoogleAccessToken = async () => {
const signedJwt = getSignedJwt();
const body = new URLSearchParams();
body.append("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
body.append("assertion", signedJwt);
const response = await fetch(authUrl, {
method: "post",
headers: {
Authorization: `Bearer ${signedJwt}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body,
});
return response.json();
};
(async () => {
const tokenResp = await getGoogleAccessToken();
console.log(tokenResp);
})();