创建签名网址

时间:2016-09-11 09:11:55

标签: google-cloud-storage google-cloud-platform

尝试为存储桶资源生成签名URL时,我收到了SignatureDoesNotMatch错误。我已经查看了GCP github项目中的示例,并查看了其他帖子中的代码来调整我的内容,但我仍然不知道如何签署我的数据。

错误回复:

<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
</Message>
<StringToSign>
GET 2944813518 /bucketName/file.mp3
</StringToSign>
</Error>

代码

public String getSignedURL(String objectName, String contentType){
        long timeStamp = System.currentTimeMillis() / 1000L;
        timeStamp = timeStamp + (3600 * 24 * 365 * 1000);
        String dataToBeSigned = "GET\n" + contentType +"\n" + timeStamp + "\n" + "/" + settings.getStorageBucketName() + "/" + objectName;
        System.out.println(dataToBeSigned);
        String signature = signData(dataToBeSigned);
        String urlEncodedSignature = URLEncoder.encode(signature, "UTF-8");

        return new StringBuilder("https://storage.googleapis.com")
                .append("/")
                .append(settings.getStorageBucketName())
                .append("/")
                .append(objectName)
                .append("?GoogleAccessId=")
                .append(settings.getStorageServiceAccountId())
                .append("&Expires=")
                .append(timeStamp)
                .append("&Signature=")
                .append(urlEncodedSignature).toString();
}

private String signData(String dataToBeSigned) {
        Signature signer = Signature.getInstance("SHA256withRSA");
        signer.initSign(getPrivateKey());
        signer.update(dataToBeSigned.getBytes("UTF-8"));
        byte[] rawSignature = signer.sign();
        String base64EncodedSignature = new String(Base64.encodeBase64(rawSignature,false),"UTF-8");
        return base64EncodedSignature;
}

private PrivateKey getPrivateKey()  {       
        InputStream inputStream = new FileInputStream(settings.getStorageAccessKeyLocation());
        String password = settings.getStorageAccessKeyPassword();
        return SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), inputStream, password, "privatekey", password);

}

1 个答案:

答案 0 :(得分:0)

  1. 如果您使用Spring,则对GCP URL进行签名的最简单方法是通过GCP SDK https://cloud.google.com/storage/docs/reference/libraries#client-libraries-usage-java

spring-cloud-gcp-starter-storage

要与GCP集成,请在application.yml中定义属性:

spring:
  cloud:
    gcp:
      project-id: PROJECT_ID
      credentials:
        location: classpath:GCP_SERVICE_ACCOUNT_KEY.json
    @Autowired
    private Storage storage;

    public String getSignedUrlToWinReleasesBucketViaSdk() {
        GoogleStorageResource googleStorageResource = new GoogleStorageResource(storage, "gs://BUCKET_NAME");

        URL signedUrl = googleStorageResource.getBucket().get("OBJECT_NAME")
                .signUrl(15, TimeUnit.MINUTES);

        return signedUrl.toString();
    }
  1. 没有GCP SDK的解决方案:
 public String getSignedUrlToWinReleasesBucket(String bucketName, String objectName) {
       
        String expirationTime = nowPlusMinutes(15);

        String urlTemplate = "GET" + "\n"
                + "" + "\n"
                + "" + "\n"
                + expirationTime + "\n"
                + "/" + bucketName + "/" + objectName;

        String signature = getSignedString(urlTemplate, privateKey());

        // URL encode the signed string so that we can add this URL
        signature = URLEncoder.encode(signature, StandardCharsets.UTF_8);

        String signedUrl = baseStorageUrl + "/" + bucketName + "/" + objectName
                + "?GoogleAccessId=" + gcpStorageClientEmail
                + "&Expires=" + expirationTime
                + "&Signature=" + signature;

        return signedUrl;
    }

    private static String nowPlusMinutes(int minutes) {
        long now = System.currentTimeMillis();
        long expiredTimeInSeconds = (now + 60 * 1000L * minutes) / 1000;
        return String.valueOf(expiredTimeInSeconds);
    }

    private static String getSignedString(String input, PrivateKey privateKey) {
        try {
            Signature privateSignature = Signature.getInstance("SHA256withRSA");
            privateSignature.initSign(privateKey);
            privateSignature.update(input.getBytes(StandardCharsets.UTF_8));
            byte[] s = privateSignature.sign();
            return Base64.encodeBase64String(s);
        } catch (GeneralSecurityException e) {
            throw new Exception("Cannot sign url with GCP Storage private key.", e, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private PrivateKey privateKey() {
        String key = gcpStoragePrivateKey
                .replaceAll("-----END PRIVATE KEY-----", "")
                .replaceAll("-----BEGIN PRIVATE KEY-----", "")
                .replaceAll("\n", "");
        byte[] keyDecoded = Base64.decodeBase64(key);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyDecoded);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(spec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new Exception("Cannot get GCP Storage private key.", e, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }