这是我的代码。我已交换了虚假服务帐户 JSON 凭据,但保留了 JSON 对象的所有属性以及每个值的通用字符集。该代码为我生成了一个签名的 JWT,但当我实际使用 cfhttp POST 提交它时,响应是
{ "error": "invalid_request", "error_description": "Bad Request" }
。有人对我在这里可能做错的有什么想法吗?预先感谢您的帮助!该代码主要是根据此处的 Firebase 示例模板化的:Creating JWT in Coldfusion for google Service account
<cfscript>
variables.service_json = deserializeJSON(
'{
"type": "service_account",
"project_id": "my-project-123456",
"private_key_id": "11111aa22222bb33333cc44444dd55555ee66666",
"private_key": "-----BEGIN PRIVATE KEY-----\naaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000==\n-----END PRIVATE KEY-----\n",
"client_email": "my-service-account-email@my-project-123456.iam.gserviceaccount.com",
"client_id": "111222333444555666777",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/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/my-service-account-email%40my-project-123456.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}'
);
variables.timestamp = dateDiff("s", CreateDate(1970,1,1), now());
variables.timestampUTC = timestamp + 8*60*60; //add 8 hours to convert to utc
//generate jwt
variables.jwt_header = {
'alg': 'RS256',
'typ': 'JWT'
};
variables.jwt_header = serializeJSON(variables.jwt_header);
variables.jwt_header = toBase64(variables.jwt_header);
variables.jwt_claim = {
'iss': service_json.client_email,
'scope': 'https://www.googleapis.com/auth/analytics.readonly',
'aud': 'https://oauth2.googleapis.com/token',
'iat': timestampUTC,
'exp': (timestampUTC + 3600)
};
variables.jwt_claim = serializeJSON(variables.jwt_claim);
variables.jwt_claim = toBase64(variables.jwt_claim);
variables.jwt = variables.jwt_header & '.' & variables.jwt_claim;
//sign jwt
variables.keyText = reReplace( service_json.private_key, "-----(BEGIN|END)[^\r\n]+", "", "all" );
variables.keyText = trim( keyText );
variables.privateKeySpec = createObject( "java", "java.security.spec.PKCS8EncodedKeySpec" ).init(binaryDecode( variables.keyText, "base64" ));
variables.privateKey = createObject( "java", "java.security.KeyFactory" ).getInstance( javaCast( "string", "RSA" ) ).generatePrivate( privateKeySpec );
variables.signer = createObject( "java", "java.security.Signature" ).getInstance( javaCast( "string", 'SHA256withRSA' ));
variables.signer.initSign( variables.privateKey );
variables.signer.update( charsetDecode( variables.jwt, "utf-8" ) );
variables.signedBytes = signer.sign();
variables.signedBase64 = toBase64(signedBytes);
variables.jwt_signed = variables.jwt & '.' & variables.signedBase64;
</cfscript>
<cfhttp url="https://oauth2.googleapis.com/token" method="POST" result="res">
<cfhttpparam type="formfield" name="grant_type" value="urn:ietf:params:oauth:grant-type:jwt-bearer">
<cfhttpparam type="formfield" name="assertion" value="#variables.jwt_signed#">
</cfhttp>
<cfdump var="#variables.jwt_signed#">
<cfdump var="#res#">
我已经尝试了一系列选项,但我需要使用服务帐户,而不是 OAuth 2.0 客户端 ID。在服务帐户方法中,我尝试使用 Ben Nadel 的 https://github.com/bennadel/JSONWebTokens.cfc,但这需要 google oauth2 不提供的公钥。所以我最好/最接近的尝试是我在这里发布的代码。
不确定它有什么不同,但我注意到你正在发布我在正文中发送的变量...
// 最终转换为 URL 编码对 var TransformedRequest = 'grant_type=#URLEncodedFormat(grantType)#&assertion=#URLEncodedFormat(jwt_signed)#';
// POST 到 auth 端点 cfhttp(method='POST', charset='utf-8', url='https://oauth2.googleapis.com/token', result='response') { cfhttpparam(type='header', name='Content-Type', value='application/x-www-form-urlencoded'); cfhttpparam(type='body', value=transformedRequest); }