我有一个关于使用 JWT 获取 Google Analytics 刷新令牌的问题。
请参考下面的示例代码,该代码工作正常,我能够获取 Analytics 对象,使用它我能够访问 Analytics 数据。
GoogleCredential credentialGA = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("$#$@#$#$#[email protected]")
.setServiceAccountScopes(Collections.singleton(AnalyticsScopes.ANALYTICS_READONLY))
.setServiceAccountPrivateKeyFromP12File(new File("$#$#$%$%$%$-privatekey.p12"))
.build();
this.analytics = new Analytics.Builder(httpTransport, JSON_FACTORY, credentialGA).setApplicationName("Demo App").build();
如果我调用 credentialGA.getAccessToken() 它会返回一个字符串。但是调用 credentialGA.getRefreshToken() 它总是返回 null。 现在,按照说法,如果我必须使用此 Analytics 对象进行进一步调用,我需要拥有刷新令牌,使用它我可以再次创建 GoogleCredential 对象来获取 Analytics 对象。
因此,我按照https://developers.google.com/accounts/docs/OAuth2ServiceAccount中提到的步骤创建了一个 JWT。然后,该 JWT 将用于进行刷新令牌调用。 此链接上共享的示例解释了如何通过 servlet/jsp/http 实现这一点。 https://code.google.com/p/gwdg-java/source/browse/src/java/com/google/iapsample/?r=a52c4e72381b1fc959053e3a1fc8c585ae2d7112
是否有任何示例代码可以解释使用 Java 独立应用程序使用 JWT 实现刷新令牌调用的相同任务。
提前致谢。
问候, 普拉塔梅什
生成 JWT 的代码:
private final static Charset UTF8_CHARSET = Charset.forName("UTF-8");
private static KeyStore myStore = null;
private static FileInputStream in_cert = null;
public static void main(String[] args) {
PrivateKey privateKey = null;
try {
in_cert = new FileInputStream(
"D://Google Analytics//ClientLogin//Analytics//%#$%#$%$^%^%$&^%&$-privatekey.p12");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
myStore = KeyStore.getInstance("PKCS12");
myStore.load(in_cert, "notasecret".toCharArray());
Enumeration<String> aliases = myStore.aliases();
String alias = "";
Enumeration objEnumeration = myStore.aliases();
while (objEnumeration.hasMoreElements() == true) {
alias = (String) objEnumeration.nextElement();
privateKey = (PrivateKey) myStore.getKey(alias,
"notasecret".toCharArray());
if(privateKey != null){
System.out.println("PRIVATE KEY:" + privateKey.toString());
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
JsonObject header = new JsonObject();
header.addProperty("alg", "RS256");
header.addProperty("typ", "JWT");
String headerStr = header.toString();
JsonObject claim = new JsonObject();
claim.addProperty("iss", "%^@%@^%$%@developer.gserviceaccount.com");
claim.addProperty("scope", "https://www.googleapis.com/auth/devstorage.readonly");
claim.addProperty("aud", "https://accounts.google.com/o/oauth2/token");
claim.addProperty("exp", "1384497516");
claim.addProperty("iat", "1384597516");
String claimStr = claim.toString();
try {
byte[] headerArr = headerStr.getBytes(UTF8_CHARSET);
System.out.println(Base64.encodeBase64String(headerArr));
byte[] claimArr = claimStr.getBytes(UTF8_CHARSET);
System.out.println(Base64.encodeBase64String(claimArr));
String inputStr = Base64.encodeBase64String(headerArr) + "." + Base64.encodeBase64String(claimArr);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(inputStr.getBytes(UTF8_CHARSET));
} catch (Exception e) {
e.printStackTrace();
}
然后复制此 JWT 字符串并在另一个程序员中使用它来请求刷新令牌,如下所示:
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("<link i have posted in the comment>");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("grant_type",
"urn:ietf:params:oauth:grant-type:jwt-bearer"));
nameValuePairs.add(new BasicNameValuePair("assertion",
"<JWT Calculated earlier>"));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
if (line.startsWith("Auth=")) {
String key = line.substring(5);
}
}
} catch (IOException e) {
e.printStackTrace();
}
成功的 API 调用实际上需要的是访问令牌。对于服务帐户,您可以通过使用私钥签署 JWT 并将其发送到accounts.google.com 来获取访问令牌。
看起来你上面的代码应该可以做到这一点。
刷新令牌是另一回事。在最终用户授权您的应用程序访问其数据后,Google 将向您的应用程序提供此信息。与上面的私钥类似,它可用于获取访问令牌,然后将其用于后续 API 调用。
简单地说,对于服务帐户用例(这就是代码片段所示的内容),您根本不需要看到刷新令牌。您具体想做什么?
我认为您可以通过调用
来检查 accessToken 的有效性https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={accessToken}
端点并再次创建 JWT 并获取 accessToken。
我知道有点晚了,但我需要实现自己的 JWT 生成来访问 firebase 云消息,并且注意到您的代码中缺少此内容:
byte[] sig = signature.sign();
正确签署 JWT。
整体:
jwt = Base64.getUrlEncoder().encodeToString(headerStr.getBytes(Charset.forName("UTF-8"))) + "."
+ Base64.getUrlEncoder().encodeToString(claimStr.getBytes(Charset.forName("UTF-8")));
String inpSign = new String(jwt);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(inpSign.getBytes(Charset.forName("UTF-8")));
byte[] sig = signature.sign();
jwt = jwt + "."+ Base64.getUrlEncoder().encodeToString(sig);