如何为 Google Cloud Storage 对象生成公共链接?
- 通过console 手动创建服务帐户并生成
.p12 密钥文件。
- 用户将文件上传到使用以下命令生成的 URL 后:
blobstoreService.createUploadUrl("/fileUploadingHandler",
UploadOptions.Builder.withMaxUploadSizeBytes(1024*1024*10) // 10 MB max
.googleStorageBucketName(BUCKET_NAME));
servlet(处理/fileUploadingHandler)可以检索 GCS 对象的文件名并生成一个临时签名的公共链接,如下所示:
Map<String, List<FileInfo>> fileInfoMap = blobstoreService.getFileInfos(request);
List<FileInfo> fileInfos = fileInfoMap.get("fileName");
FileInfo fileInfo = fileInfos.get(0);
String[] parts = fileInfo.getGsObjectName().split("/"); // get rid of /gs/buck_name/
String fileName = parts[parts.length - 1];
String signedUrl = GcsUrlSigner.generateSignedUrl(fileName);
// send the temporary public link (signedUrl) back to the user
import com.google.api.client.util.Base64;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
/**
* Created by Fouad on 22-Dec-15.
*/
public class GcsUrlSigner
{
private static final String DEFAULT_BUCKET_NAME = "XXXXXXXX.appspot.com";
private static final String PUBLIC_URL_SERVICE_ACCOUNT_EMAIL = "XXXXXXXX@XXXXXX.iam.gserviceaccount.com";
private static final String PUBLIC_URL_SERVICE_ACCOUNT_PKCS12_FILE_PATH = "XXXXXX.p12"; // located in the same folder as GcsUrlSigner.java
private static final String PUBLIC_URL_SERVICE_ACCOUNT_PKCS12_FILE_PASSWORD = "notasecret";
private static final long PUBLIC_URL_EXPIRATION_SECONDS = System.currentTimeMillis() / 1000 + 60; // 60 seconds
public static String generateSignedUrl(String objectName) throws Exception
{
return generateSignedUrl(DEFAULT_BUCKET_NAME, objectName);
}
public static String generateSignedUrl(String bucketName, String objectName) throws Exception
{
PrivateKey key = loadKeyFromPkcs12(PUBLIC_URL_SERVICE_ACCOUNT_PKCS12_FILE_PATH, PUBLIC_URL_SERVICE_ACCOUNT_PKCS12_FILE_PASSWORD.toCharArray());
return getSigningURL(key, "GET", PUBLIC_URL_EXPIRATION_SECONDS, bucketName, objectName);
}
private static String getSigningURL(PrivateKey key, String verb, long expirationSeconds, String bucketName, String objectName) throws Exception
{
String url_signature = signString(key, verb + "\n\n\n" + expirationSeconds + "\n" + "/" + bucketName + "/" + objectName);
String signed_url = "https://storage.googleapis.com/" + bucketName + "/" + objectName +
"?GoogleAccessId=" + PUBLIC_URL_SERVICE_ACCOUNT_EMAIL +
"&Expires=" + expirationMillis +
"&Signature=" + URLEncoder.encode(url_signature, "UTF-8");
return signed_url;
}
private static PrivateKey loadKeyFromPkcs12(String filename, char[] password) throws Exception
{
InputStream is = GcsUrlSigner.class.getResourceAsStream(PUBLIC_URL_SERVICE_ACCOUNT_PKCS12_FILE_PATH);
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(is, password);
return (PrivateKey) ks.getKey("privatekey", password);
}
private static String signString(PrivateKey key, String stringToSign) throws Exception
{
if(key == null) throw new Exception("Private Key not initalized");
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initSign(key);
signer.update(stringToSign.getBytes("UTF-8"));
byte[] rawSignature = signer.sign();
return new String(Base64.encodeBase64(rawSignature), "UTF-8");
}
}