向Google Cloud Storage API 提供凭据

9
我正在尝试编写一个“hello world”程序,以测试谷歌云存储。我的目标是编写最简单的程序,只需将硬编码文件上传到云存储即可。
我已经搜索了互联网寻找基本教程,但我找到的最接近的是这个用于在App Engine中使用云存储的指南。我已经编写了下面的程序:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;

import com.google.cloud.storage.Acl;
import com.google.cloud.storage.Acl.Role;
import com.google.cloud.storage.Acl.User;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

public class Main {
    public static void main(String[] args) throws FileNotFoundException{

        FileInputStream fileInputStream = new FileInputStream("my-file.txt");

        Storage storage = StorageOptions.getDefaultInstance().getService();

        BlobInfo blobInfo =
            storage.create(
                BlobInfo
                    .newBuilder("my-cloud-storage-bucket", "my-file.txt")
                    .setAcl(new ArrayList<>(Arrays.asList(Acl.of(User.ofAllUsers(), Role.READER))))
                    .build(),
                fileInputStream);

        String fileUrl = blobInfo.getMediaLink();

        System.out.println("Uploaded URL: " + fileUrl);
    }
}

当我运行该代码时,在调用storage.create()时,出现了401未经授权的错误,这并不奇怪,因为我没有提供用户名或密码。我猜想这是因为示例正在App Engine中运行,以这种方式提供凭据。
我尝试通过属性文件传递我的凭据:
Credential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId("accountId")
                .setServiceAccountPrivateKeyFromP12File(
                        new File("PRIVATE_KEY_PATH"))
                .setServiceAccountScopes(scopes).build();

Storage storage = new StorageOptions.DefaultStorageFactory().create(StorageOptions.newBuilder().setCredentials(credential).build());

但是这段代码不能编译,因为setCredentials()函数需要一个Credentials实例,而不是Credential实例。
我一直在谷歌搜索和阅读Cloud Storage API,但我仍然无法弄清楚应该如何传入凭据,而不需要经过复杂的设置过程。
所以,我的问题是:提供凭证给Google Cloud存储以上传文件的最简单方法是什么?
背景信息:我正在尝试比较和对比Google Cloud Storage和Amazon S3。我可以轻松地在S3中创建此类程序,但出于某种原因,我在Cloud Storage中遇到了障碍。非常感谢任何人能够提供的见解或基本教程。

请参阅 https://cloud.google.com/docs/authentication/getting-started#auth-cloud-implicit-java。 - jarmod
2个回答

18

似乎使用新的Google Cloud客户端库从PKCS #12文件创建凭据不像以前使用旧的Cloud Storage JSON API那样容易。

最简单的方法是改用JSON格式,如此处所述,然后使用GoogleCredentials#fromStream方法加载它:

Credentials credentials = GoogleCredentials.fromStream(new FileInputStream("credentials.json"));
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

如果您仍想使用PKCS#12,我相信这个方法可以解决问题:
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(
    SecurityUtils.getPkcs12KeyStore(), new FileInputStream("credentials.p12"), "notasecret", "privatekey", "notasecret");
Credentials credentials = new ServiceAccountCredentials(null, "accountId", privateKey, null, null);
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

谢谢回复。在你的代码片段中,“notasecret”和“scopes”是什么? - Cat Grass
我在文档中查找了一下,看起来那些是密钥文件的密码?我的文件没有密码保护,所以我尝试使用PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), new FileInputStream("MyWebApp.json"), null, null, null);,但这会在SecurityUtils.java:82处导致NPE。你有什么建议用于这些参数吗? - Cat Grass
如果您是从Google Cloud Console生成凭据,则不应更改这些参数。 notasecret是Google实际使用的密码:https://support.google.com/cloud/answer/6158849?hl=en#serviceaccounts - Helder Pereira
我尝试了这个:PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), new FileInputStream("MyWebApp.json"), "notasecret", "private_key", "notasecret"); 但是我得到了这个错误:java.io.IOException: toDerInputStream rejects tag type 123 at sun.security.util.DerValue.toDerInputStream(DerValue.java:847) at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1915) at KeyStore.load(KeyStore.java:1445) at SecurityUtils.loadKeyStore(SecurityUtils.java:82) at SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.java:115) - Cat Grass
正如我在答案中所写,如果您的凭据是以JSON格式提供的,请使用GoogleCredentials.fromStream(new FileInputStream("MyWebApp.json"))来加载它们。我发布的代码片段是针对P12格式的情况,因为我假设您在问题中使用了setServiceAccountPrivateKeyFromP12File方法。 - Helder Pereira
1
哇,太感谢了!这正是我在寻找的。 - Cat Grass

7
谷歌云平台的Java客户端库(Google Cloud client library for Java)可以使用多种认证方案,但最简单的方法是利用“应用程序默认凭据”(Application Default Credentials)。这些凭据与您的应用引擎应用程序运行的服务帐号相关联。如果您在应用程序引擎或计算引擎上使用谷歌云(google-cloud)Java客户端库,则以下内容应该可以正常工作:
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

Storage storage = StorageOptions.getDefaultInstance().getService();
BlobId blobId = BlobId.of("bucket", "blob_name");
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("text/plain").build();
Blob blob = storage.create(blobInfo, "Hello, Cloud Storage!".getBytes(UTF_8));

这可能是使用认证的最简单的方法。如果您正在本地运行程序而不是部署到Google环境中,您也可以安装gcloud命令行实用程序,然后运行gcloud auth application-default login,此时应用程序默认凭据应使上述代码能够作为您进行身份验证,无需任何显式的身份验证逻辑。
如果您想以编程方式指定特定的服务帐户并具有与之关联的JSON密钥文件,则可以像下面这样明确执行:
Storage storage = StorageOptions.newBuilder()
    .setCredentials(ServiceAccountCredentials.fromStream(
         new FileInputStream("/path/to/my/key.json")))
    .build()
    .getService();

您还可以通过使用环境变量 GOOGLE_APPLICATION_CREDENTIALS 指定服务账号私钥的路径。例如:

$> GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json java MyApp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接