我一直在解决这个问题,并向任何指导开放。我有一个Angular 4应用程序,我使用Oauth创建对Google Cloud Datastore服务帐户的访问权限。我正在使用JWT并对其进行编码以传递给Google。以下是签名和HTTP请求的功能。
我不确定编码是否不正确,或者我是否尝试错误地访问API。打开我可能出错的地方的任何建议,或者更好的方法,这不会涉及到节点的背负。
获取令牌的功能:
getGoogleToken(){
let key = this.createGoogleSig();
let params = {
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: key
};
let myheaders = new Headers;
myheaders.append('Content-Type', 'application/x-www-form-urlencoded')
console.log(params);
this.http.post('https://www.googleapis.com/oauth2/v4/token', params, { headers : myheaders}).subscribe(
data => this.thing = data.toString(),
err => console.log(err),
() => console.log('Request Complete')
);
}
创建签名的代码
createGoogleSig(){
let now = (Date.now() / 1000).toFixed(0);
let exp = +now + 1800;
let key = {
"type": "service_account",
"project_id": "jenenginecms",
"private_key_id": "---",
"private_key": "-----BEGIN PRIVATE KEY-----cut for brevity---END PRIVATE KEY-----\n",
"client_email": "pepperbirdcms@jenenginecms.iam.gserviceaccount.com",
"client_id": "---",
"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": "https://www.googleapis.com/robot/v1/metadata/x509/pepperbirdcms%40jenenginecms.iam.gserviceaccount.com"
}
let claimObj = {
"iss": key.client_email,
"scope": "https://www.googleapis.com/auth/datastore",
"aud": "https://www.googleapis.com/oauth2/v4/token",
"exp": exp,
"iat": +now
}
console.log(claimObj);
let header = Base64.encodeURI('{"alg":"RS256","typ":"JWT"}');
let claimSet = Base64.encodeURI(JSON.stringify(claimObj));
let sig = new KJUR.crypto.Signature({ "alg": "SHA256withRSA" });
let privateKey = key.private_key;
let ret = encryptSignature();
let jwt = header + "." + claimSet + "." + ret;
console.log(jwt)
return jwt;
function encryptSignature() {
sig.init(privateKey);
sig.updateString(header + "." + claimSet);
let cleaned_hex = sig.sign()
let input = new Array();
for (let i = 0; i < cleaned_hex.length / 2; i++) {
let h = cleaned_hex.substr(i * 2, 2);
input[i] = parseInt(h, 16);
}
let base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
let ret = '';
let i = 0;
let j = 0;
let char_array_3 = new Array(3);
let char_array_4 = new Array(4);
let in_len = input.length;
let pos = 0;
while (in_len--) {
char_array_3[i++] = input[pos++];
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars.charAt(char_array_4[i]);
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++)
char_array_3[j] = 0;
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars.charAt(char_array_4[j]);
while ((i++ < 3))
ret += '=';
}
return ret;
}
}
答案 0 :(得分:1)
实际上完整的错误非常有用:)
以此请求为例:
POST https://www.googleapis.com/oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
当我执行此操作时,我
{
"error": "invalid_request",
"error_description": "Missing required parameter: assertion"
}
这是一个错误,但是“完全没问题,因为它是一个不同的错误。它证明Google认可此授权类型。现在看一下你的错误信息:
"error_description": "Invalid grant_type: "
描述字符串以冒号和空格结尾。这表明服务器未收到请求正文或无法解释它。为了证明这一点,我发送了另一个请求,这次是grant_type=thisdoesntexist
,我得到了这个:
{
"error": "unsupported_grant_type",
"error_description": "Invalid grant_type: thisdoesntexist"
}
这意味着您的POST请求存在缺陷。我可以看到两个可能的问题:
标头设置不正确。像您一样使用Content-type: application/x-www-form-urlencoded
是正确的想法,但是标题可能没有正确附加到您的请求中?
请求正文设置不正确。
我建议您仔细检查一下您是否正确实施了this.http.post
来电,特别是我不知道应该做什么的data => this.thing = data.toString(),
行。
如果通过这样做您没有发现任何错误,您可以尝试监控您的请求。为此,您可以使用Fiddler之类的工具,也可以在本地Web服务器上快速设置脚本,只需回显标题和消息正文/ POST参数,并在应用内调用它,替换{{1} }。