我们有一个在GCP上运行的ERP应用程序。 要下载超过三个月左右的数据,我们正在GCS上载文件。现在,我想创建一个签名的URL,以便为最终用户提供有限的访问权限。 我一直在尝试这个。但是我得到这个错误: 签名不匹配。请检查您的Google密钥。 谁能告诉我该怎么做?
private static final int EXPIRATION_TIME = 5;
private static final String BASE_URL = "https://storage.googleapis.com";
private static final String httpVerb = "GET";
/*
* private static final String BUCKET = "my_bucket"; private static final String
* FOLDER = "folder";
*/
private final AppIdentityService identityService = AppIdentityServiceFactory.getAppIdentityService();
public String getSignedUrl(String bucket, final String fileName, String contentTpe) throws Exception {
final long expiration = expiration();
final String unsigned = stringToSign(bucket, expiration, fileName, contentTpe);
final String signature = sign(unsigned);
return new StringBuilder(BASE_URL).append("/").append(bucket).append("/").append(fileName)
.append("?GoogleAccessId=").append(clientId()).append("&Expires=").append(expiration)
.append("&Signature=").append(URLEncoder.encode(signature, "UTF-8")).toString();
}
private static long expiration() {
final long unitMil = 1000l;
final Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, EXPIRATION_TIME);
final long expiration = calendar.getTimeInMillis() / unitMil;
return expiration;
}
private String stringToSign(String bucket, final long expiration, String filename, String contentType) {
final String contentMD5 = "";
final String canonicalizedExtensionHeaders = "";
final String canonicalizedResource = "/" + bucket + "/" + filename;
final String stringToSign = httpVerb + "\n"+ contentMD5 + "\n" + contentType + "\n" + expiration + "\n"
+ canonicalizedExtensionHeaders + canonicalizedResource;
return stringToSign;
}
protected String sign(final String stringToSign) throws UnsupportedEncodingException {
final SigningResult signingResult = identityService.signForApp(stringToSign.getBytes());
final String encodedSignature = new String(Base64.encodeBase64(signingResult.getSignature()), "UTF-8");
return encodedSignature;
}
protected String clientId() {
return identityService.getServiceAccountName();
}
答案 0 :(得分:0)
URL签名代码有些棘手,因为从本质上讲,除了仅仅看到错误之外,很难知道您犯了什么错误。有一些通用的技巧可以使您更轻松:
首先,如果可能的话,请考虑在google-cloud库中使用URL签名功能。例如,Java google-cloud library提供了一个Storage.signURL方法,您可以像这样使用它:
URL signedUrl = storage.signUrl(
BlobInfo.newBuilder(bucketName, blobName).build(),
2, TimeUnit.DAYS);
第二,如果您查看错误消息,您会注意到其中有一个<StringToSign>
部分。本部分包含GCS将为其计算签名的确切字符串。确保您要签名的字符串与该字符串完全匹配。如果没有,那是你的问题。
在您的代码的特殊情况下,我没有发现问题,但可能是在对字符串进行签名时您包括了内容类型行,但是GET请求未提供Content-Type标头。不过,这只是一个主意,因为我看不到您对getSignedUrl的调用。