- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想要做的是生成一个 JWT,用于在我部署的 GCP 云函数上调用 HTTP 触发器。我已经使用“allUsers”部署了我的函数并验证了它的工作原理,但我希望它更安全,因此我需要将 JWT 附加到我的 HTTP 请求。我正在关注this code以下片段大部分来自于此。我想我已经很接近了,但还没有完全实现。在下面的所有示例等中,我已将项目名称更改为 PROJECT_NAME。
首先,我创建了一个名为 testharness-sa 的服务帐户并下载了其 key 文件。当我运行测试时,我有一个环境变量 GOOGLE_APPLICATION_CREDENTIALS 指向该文件。然后我运行了以下命令:
gcloud functions add-iam-policy-binding gopubsub \
--member='serviceAccount:testharness-sa@PROJECT_NAME.iam.gserviceaccount.com' \
--role='roles/cloudfunctions.invoker'
这通过列出我的云函数上的所有当前绑定(bind)(包括 testharness-sa)给了我确认。
我的代码的核心是这样的:
private String getSignedJwt() {
GoogleCredentials credentials = GoogleCredentials
.getApplicationDefault()
.createScoped(Collections.singleton(IAM_SCOPE));
long now = System.currentTimeMillis();
RSAPrivateKey privateKey = (RSAPrivateKey) credentials.getPrivateKey();
Algorithm algorithm = Algorithm.RSA256(null, privateKey);
return JWT.create()
.withKeyId(credentials.getPrivateKeyId())
.withIssuer(credentials.getClientEmail())
.withSubject(credentials.getClientEmail())
.withAudience(OAUTH_TOKEN_AUDIENCE)
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + EXPIRATION_TIME_IN_MILLIS))
.withClaim("target_audience", clientId)
.sign(algorithm);
}
这给了我一个签名的 JWT。据我了解,这用于调用 GCP 来获取最终的 JWT,我可以用它来调用我的云函数。
生成签名的 JWT 后,我会像这样使用它:
String jwt = getSignedJwt();
final GenericData tokenRequest = new GenericData()
.set("grant_type", JWT_BEARER_TOKEN_GRANT_TYPE)
.set("assertion", jwt);
final UrlEncodedContent content = new UrlEncodedContent(tokenRequest);
final HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
final HttpRequest request = requestFactory
.buildPostRequest(new GenericUrl(OAUTH_TOKEN_URI), content)
.setParser(new JsonObjectParser(JacksonFactory.getDefaultInstance()));
HttpResponse response = request.execute();
...
因此它获取签名的 JWT 并发出请求以获取最终的 JWT,然后...失败。错误是“无效的 JWT:受众检查失败”看起来我的参数不好,所以让我们看看我的参数(它们实际上是常量,而不是参数):
private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";
//"https://www.googleapis.com/auth/cloud-platform";
private static final String OAUTH_TOKEN_URI = "https://oauth2.googleapis.com/token";
//"https://www.googleapis.com/oauth2/v4/token";
private static final String OAUTH_TOKEN_AUDIENCE = "https://us-central1-PROJECT_NAME.cloudfunctions.net/gopubsub";
//"https://www.googleapis.com/token";
private static final String JWT_BEARER_TOKEN_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer";
private static final long EXPIRATION_TIME_IN_MILLIS = 3600 * 1000L;
我添加了其他变体作为针对常量的注释。
根据错误消息,我使用的受众群体值似乎是错误的。 This page建议受众应该是服务帐户电子邮件,我想我在其他地方看到它应该是云功能的 URL,但这些都不适合我。
我知道这可以工作,因为我可以发出这个命令:
gcloud auth print-identity-token
这给了我最终的 JWT(只要我有 GOOGLE_APPLICATION_CREDENTIALS 指向我的 json 文件)。我可以将该 JWT 粘贴到curl 命令中并成功调用 HTTP 触发器,如果我将 JWT 排除在外,则会失败,因此我知道 JWT 正在被检查。但到目前为止,我不知道如何从我的 Java 代码中执行与 gcloud auth print-identity-token 等效的操作。有人知道吗?
最佳答案
尽管有错误消息,但我发现答案与范围无关。它实际上与我传递的 clientId 值相关(虽然在代码中存在,但我的问题中并未真正提及)。我使用的是在服务帐户 json 文件中找到的值,这是一串非常长的数字。这就是问题所在。它必须是我的 HTTP 触发器的 URL。所以这些是我最终得到的常量:
private static final String IAM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
private static final String OAUTH_TOKEN_URI = "https://www.googleapis.com/oauth2/v4/token";
private static final String OAUTH_TOKEN_AUDIENCE = "https://www.googleapis.com/oauth2/v4/token";
private static final String JWT_BEARER_TOKEN_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer";
private static final long EXPIRATION_TIME_IN_MILLIS = 3600 * 1000L;
事实上,如果我删除对 IAM_SCOPE
的所有引用,它仍然有效,所以我认为这并不重要。将其组合在一起的代码现在如下所示:
return JWT.create()
.withKeyId(credentials.getPrivateKeyId())
.withIssuer(credentials.getClientEmail())
.withSubject(credentials.getClientEmail())
.withAudience(OAUTH_TOKEN_AUDIENCE)
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + EXPIRATION_TIME_IN_MILLIS))
.withClaim("target_audience", targetURL)
.sign(algorithm);
具体的更改是 withClaim()
调用,它现在包含我要调用的 URL。完成此操作后,代码将返回我想要的 JWT,事实上,当我调用安全的 HTTP 触发器 URL 时,它确实可以工作。希望对其他人有帮助。
关于java - 如何为 Cloud Function HTTP 触发器生成 JWT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61037206/
我是一名优秀的程序员,十分优秀!