google-cloud-platform - 如何使用 JAVA 使用 REST API 从服务帐户凭据创建访问令牌?
问题描述
我需要在不使用 GCP Java 客户端库的情况下使用服务帐户凭据列出文件夹。我需要使用 REST API 调用,因为使用 GCP Java 客户端库有限制。是否有任何示例或示例可以参考在 Java/Spring 中进行 REST API 调用?
解决方案
您可以使用 RestTemplate 和这个依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.14.0</version>
</dependency>
然后,阅读您的服务帐户 JSON 文件(这里是我的key.json
文件),尽情享受吧!如果某些部分不清楚,请告诉我!
InputStream resource = new ClassPathResource("key.json").getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(resource));
String keyFileJson = reader.lines().collect(Collectors.joining("\n"));
Map keyFile = new ObjectMapper().readValue(keyFileJson, Map.class);
String privKeyPEM = keyFile.get("private_key").toString().replace("-----BEGIN PRIVATE KEY-----","")
.replace("-----END PRIVATE KEY-----","")
.replaceAll("\n","");
byte [] encoded = Base64.decode(privKeyPEM);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(keySpec);
String tokenUrl = "https://oauth2.googleapis.com/token";
long now = System.currentTimeMillis();
Algorithm algorithm = Algorithm.RSA256(null, (RSAPrivateKey)privKey);
String signedJwt = JWT.create()
.withKeyId(keyFile.get("private_key_id").toString())
.withIssuer(keyFile.get("client_email").toString())
.withAudience(tokenUrl)
.withClaim("scope","openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/compute")
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + 3600 * 1000L))
.sign(algorithm);
// System.out.println(signedJwt);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("assertion", signedJwt);
map.add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(tokenUrl, entity, String.class);
Map result = new ObjectMapper().readValue(responseEntity.getBody(), Map.class);
System.out.println(result.get("access_token"));
编辑 1
要生成和获取 ID_Token,如果您要生成令牌以调用以安全模式部署的 Cloud Run、Cloud Functions 或 App Engine,则需要此选项。您需要用 target_audience URL 替换范围声明。最后,打印 id_token 而不是访问令牌
String signedJwt = JWT.create()
.withKeyId(keyFile.get("private_key_id").toString())
.withIssuer(keyFile.get("client_email").toString())
.withAudience(tokenUrl)
.withClaim("target_audience", "https://target-log-fqffbf2xsq-uc.a.run.app")
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + 3600 * 1000L))
.sign(algorithm);
...
...
...
System.out.println(result.get("id_token"));
推荐阅读
- javascript - 如何在 svelte 的 javascript 中单击按钮时调用异步函数?
- arrays - 我怎样才能在没有数组的情况下完成这项工作?
- java - 如何比较两个数组之间的值
- javascript - 使用 systemmd 运行时 fs-extra 因语法错误而失败,使用 node 命令可以正常工作
- python - 为小时数据添加日期列
- three.js - 如何沿其在three.js中指向的方向向前移动3d对象
- python-3.x - 无法在 linux 上的 docker 上部署项目
- javascript - 返回 IF ELSE IF 语句的函数
- jenkins - Jenkins 并行阶段忽略 when 语句
- reactjs - 使用 Promise.all 的多个 API 调用可以很好地在控制台中显示结果,但状态出现问题