如何计算服务帐户的 OAuth 签名?
How can I compute OAuth's signature for service account?
我想使用 HTTP/REST 方法 get a service account access token 获取 Google API,但 OAuth 向我发送了签名错误。我正在使用 Java.
我收到以下 JSON 字符串:
{
"error": "invalid_grant",
"error_description": "Invalid JWT Signature."
}
据我所知,在文档中,我需要使用 header、声明集和签名来编写 JWT(JSON Web 令牌)。我设法获得了正确的 header 和声明集,但显然,我的签名计算不正确。
我的进口:
import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.PrivateKey;
这里是header计算:
String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
byte[] bytes = header.getBytes();
header = Base64.getEncoder().encodeToString(bytes);
我的声明集:
long time_milis = System.currentTimeMillis()/1000L;
String claim_set = "{\n"
+ " \"iss\":\"something@something.iam.gserviceaccount.com\",\n"
+ " \"scope\":\"https://www.googleapis.com/auth/devstorage.read_write\",\n"
+ " \"aud\":\"https://www.googleapis.com/oauth2/v4/token\",\n"
+ " \"exp\":" + (time_milis + 300) + ",\n"
+ " \"iat\":" + time_milis + "\n"
+ "}";
bytes = claim_set.getBytes();
claim_set = Base64.getEncoder().encodeToString(bytes);
为我的签名尝试做好准备! (出于明显的安全原因,我屏蔽了私钥):
String signature = header + "." + claim_set;
String privateKeyString = "-----BEGIN PRIVATE KEY-----\nturlututu123\n-----END PRIVATE KEY-----\n";
privateKeyString = private_key.replaceAll("-----END PRIVATE KEY-----", "").replaceAll("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(
new PKCS8EncodedKeySpec(
Base64.getDecoder().decode(privateKeyString)
)
);
privateSignature.initSign(privateKey);
privateSignature.update(signature.getBytes("UTF-8"));
bytes = privateSignature.sign();
signature = Base64.getEncoder().encodeToString(bytes);
我在 https://www.googleapis.com/oauth2/v4/token 以 POST
模式发送我的请求 header :
"Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded"
并在 body 中:
"grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + header + "." + claim_set + "." + signature
我真的卡住了,不知道如何前进。
终于找到答案了!这是一个编码问题。事实上,当我对字符串进行编码时,我调用了 Base64.getEncoder()
编码器而不是 Base64.getUrlEncoder()
编码器。现在我们可以更改所有脚本了。
这里是header计算:
String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
byte[] bytes = header.getBytes();
header = Base64.getUrlEncoder().encodeToString(bytes);
我的声明集:
long time_milis = System.currentTimeMillis()/1000L;
String claim_set = "{\n"
+ " \"iss\":\"something@something.iam.gserviceaccount.com\",\n"
+ " \"scope\":\"https://www.googleapis.com/auth/devstorage.read_write\",\n"
+ " \"aud\":\"https://www.googleapis.com/oauth2/v4/token\",\n"
+ " \"exp\":" + (time_milis + 300) + ",\n"
+ " \"iat\":" + time_milis + "\n"
+ "}";
bytes = claim_set.getBytes();
claim_set = Base64.getUrlEncoder().encodeToString(bytes);
和签名(出于明显的安全原因,我屏蔽了私钥):
String signature = header + "." + claim_set;
String privateKeyString = "-----BEGIN PRIVATE KEY-----\nturlututu123\n-----END PRIVATE KEY-----\n";
privateKeyString = private_key.replaceAll("-----END PRIVATE KEY-----", "").replaceAll("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(
new PKCS8EncodedKeySpec(
Base64.getDecoder().decode(privateKeyString)
)
);
privateSignature.initSign(privateKey);
privateSignature.update(signature.getBytes("UTF-8"));
bytes = privateSignature.sign();
signature = Base64.getUrlEncoder().encodeToString(bytes);
感谢 this post 在调试过程中帮助了我。
我想使用 HTTP/REST 方法 get a service account access token 获取 Google API,但 OAuth 向我发送了签名错误。我正在使用 Java.
我收到以下 JSON 字符串:
{
"error": "invalid_grant",
"error_description": "Invalid JWT Signature."
}
据我所知,在文档中,我需要使用 header、声明集和签名来编写 JWT(JSON Web 令牌)。我设法获得了正确的 header 和声明集,但显然,我的签名计算不正确。
我的进口:
import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.PrivateKey;
这里是header计算:
String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
byte[] bytes = header.getBytes();
header = Base64.getEncoder().encodeToString(bytes);
我的声明集:
long time_milis = System.currentTimeMillis()/1000L;
String claim_set = "{\n"
+ " \"iss\":\"something@something.iam.gserviceaccount.com\",\n"
+ " \"scope\":\"https://www.googleapis.com/auth/devstorage.read_write\",\n"
+ " \"aud\":\"https://www.googleapis.com/oauth2/v4/token\",\n"
+ " \"exp\":" + (time_milis + 300) + ",\n"
+ " \"iat\":" + time_milis + "\n"
+ "}";
bytes = claim_set.getBytes();
claim_set = Base64.getEncoder().encodeToString(bytes);
为我的签名尝试做好准备! (出于明显的安全原因,我屏蔽了私钥):
String signature = header + "." + claim_set;
String privateKeyString = "-----BEGIN PRIVATE KEY-----\nturlututu123\n-----END PRIVATE KEY-----\n";
privateKeyString = private_key.replaceAll("-----END PRIVATE KEY-----", "").replaceAll("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(
new PKCS8EncodedKeySpec(
Base64.getDecoder().decode(privateKeyString)
)
);
privateSignature.initSign(privateKey);
privateSignature.update(signature.getBytes("UTF-8"));
bytes = privateSignature.sign();
signature = Base64.getEncoder().encodeToString(bytes);
我在 https://www.googleapis.com/oauth2/v4/token 以 POST
模式发送我的请求 header :
"Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded"
并在 body 中:
"grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + header + "." + claim_set + "." + signature
我真的卡住了,不知道如何前进。
终于找到答案了!这是一个编码问题。事实上,当我对字符串进行编码时,我调用了 Base64.getEncoder()
编码器而不是 Base64.getUrlEncoder()
编码器。现在我们可以更改所有脚本了。
这里是header计算:
String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
byte[] bytes = header.getBytes();
header = Base64.getUrlEncoder().encodeToString(bytes);
我的声明集:
long time_milis = System.currentTimeMillis()/1000L;
String claim_set = "{\n"
+ " \"iss\":\"something@something.iam.gserviceaccount.com\",\n"
+ " \"scope\":\"https://www.googleapis.com/auth/devstorage.read_write\",\n"
+ " \"aud\":\"https://www.googleapis.com/oauth2/v4/token\",\n"
+ " \"exp\":" + (time_milis + 300) + ",\n"
+ " \"iat\":" + time_milis + "\n"
+ "}";
bytes = claim_set.getBytes();
claim_set = Base64.getUrlEncoder().encodeToString(bytes);
和签名(出于明显的安全原因,我屏蔽了私钥):
String signature = header + "." + claim_set;
String privateKeyString = "-----BEGIN PRIVATE KEY-----\nturlututu123\n-----END PRIVATE KEY-----\n";
privateKeyString = private_key.replaceAll("-----END PRIVATE KEY-----", "").replaceAll("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(
new PKCS8EncodedKeySpec(
Base64.getDecoder().decode(privateKeyString)
)
);
privateSignature.initSign(privateKey);
privateSignature.update(signature.getBytes("UTF-8"));
bytes = privateSignature.sign();
signature = Base64.getUrlEncoder().encodeToString(bytes);
感谢 this post 在调试过程中帮助了我。