【问题标题】:generate public link for Google Cloud Storage objects为 Google Cloud Storage 对象生成公共链接
【发布时间】:2016-03-28 05:16:03
【问题描述】:

如何为用户通过 BlobStore API 提交的 Google Cloud Storage 对象生成公共链接?

【问题讨论】:

  • 您是否知道存储桶名称和对象名称,以及数据应该可以公开访问还是只能由特定最终用户访问一次?
  • @BrandonYarbrough 我正在寻找一个永久链接并且可以公开访问。但是,我阅读了有关“签名链接”的信息,它对我来说效果很好,如下面的回答所示。但是,它有限制吗?像最大到期时间戳一样?还是应该只在用户请求时生成签名链接?

标签: java google-app-engine google-cloud-storage blobstore


【解决方案1】:

有几种方法可以为公共 GCS 对象提供服务。一种是签名 URL。另一个是getServingUrl() App Engine 方法。

但是,如果对象应该对所有人可见,您可以做一些更简单的事情。将对象的权限设置为授予“AllUsers”的 READ 权限,这允许在没有任何身份验证的情况下读取对象,然后简单地将用户引用到此路径:

https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME

就是这样!

您可以从云控制台、通过 API 或使用此 gsutil 命令将对象设置为可公开读取:gsutil acl ch -g AllUsers:R gs://BUCKET_NAME/OBJECT_NAME

【讨论】:

  • 感谢您分享您的答案。关于getServingUrl(),它是ImagesService接口的方法,所以我假设它只适用于图像。我想我会向所有用户授予 READ 权限。但是,我需要自动授予权限,如何通过 API 来实现?
  • 您可以通过几种方式授予读取权限。我不确定您是如何创建这些对象的,但大多数方法都允许您在上传对象时为其指定 ACL。您还可以指定将应用于存储桶中上传对象的默认 ACL。您还可以使用 GCS API 在对象上设置 ACL。
  • 我试图为本地开发环境生成相同的,我发现它可以通过这种方式完成:http://localhost:8080/_ah/gcs/<bucket>/<object>
  • 既然 Firebase 已与 Google Cloud 集成,我们如何将 Firebase 动态链接设置为 Firebase 存储对象?请看我的问题stackoverflow.com/q/37360664/4419474
【解决方案2】:

如何为 Google Cloud Storage 对象生成公共链接?

  1. 通过console 手动创建服务帐户并生成.p12 密钥文件。
  2. 用户将文件上传到使用以下命令生成的 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");
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-30
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 2015-09-09
    • 1970-01-01
    相关资源
    最近更新 更多