【问题标题】:How to use the Google cloud platform service account key generated using serviceAccounts.keys.create API, at the client side in Java?如何在 Java 客户端使用通过 serviceAccounts.keys.create API 生成的 Google 云平台服务帐户密钥?
【发布时间】:2017-03-18 01:29:49
【问题描述】:

我正在使用 GAE 中生成的服务帐户密钥,在客户端使用 serviceAccounts.keys.create Google IAM API 将文件上传到 GCS。此 API 返回我在客户端代码中使用的 privateKeyData 字段,如下所示:

public class GCSTest {
    public static final String CLOUD_STORAGE_SCOPE =
            "https://www.googleapis.com/auth/cloud-platform";
    private GoogleCredential credential = null;
    private HttpTransport HTTP_TRANSPORT = null;
    private Storage storage = null;
    private final JsonFactory json_factory = JacksonFactory
            .getDefaultInstance();
    public String APPLICATION_NAME = "GCSTest";
    private String privKeyString =
            <copy the privateKeyData from response of serviceAccounts.keys.create>;

    public void startTests() {
        initStorageService();
        writeObject();
    }

    private void initStorageService() {
        List<String> scopeList = new ArrayList<String>();
        scopeList.add(CLOUD_STORAGE_SCOPE);
        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

        byte[] privKeyBytes = Base64.decodeBase64(privKeyString.getBytes());
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privKeyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = kf.generatePrivate(spec);
        credential =
            new GoogleCredential.Builder()
                .setTransport(HTTP_TRANSPORT)
                .setJsonFactory(json_factory)
                .setServiceAccountId(
                        "<service_account_name>@<project-id>.iam.gserviceaccount.com")
                .setServiceAccountScopes(scopeList)
                .setServiceAccountPrivateKey(privateKey)
                .setServiceAccountPrivateKeyId(
                        "<key_id>")
                .build();

        storage =
            new Storage.Builder(HTTP_TRANSPORT, json_factory,
                credential).setApplicationName(APPLICATION_NAME)
                .build();
    }
    private void writeObject() {
        String fileName = "StorageSample";
        Path tempPath = Files.createTempFile(fileName, ".txt");;
        Files.write(tempPath, "Sample file".getBytes());
        File tempFile = tempPath.toFile();
        tempFile.deleteOnExit();

        InputStreamContent contentStream =
                new InputStreamContent("text/plain", new FileInputStream(
                        tempFile));
        contentStream.setLength(tempFile.length());
        StorageObject objectMetadata = new StorageObject().setName(fileName);
        Storage.Objects.Insert insert = 
            storage.objects().insert(<bucket_name>,
                        objectMetadata, contentStream);;
        insert.setName(fileName);
        insert.execute();
    }
}

但是,当storage.objects().insert 被调用时,我得到了java.security.InvalidKeyException: invalid key format exception。 这是使用服务帐户密钥生成GoogleCredential 的正确方法吗? P.S:我知道 JSON 或 P12 密钥文件。我不想使用它,因为它不适合我的用例。

【问题讨论】:

    标签: java google-app-engine google-cloud-storage google-api-java-client service-accounts


    【解决方案1】:

    默认情况下,serviceAccounts.keys.create 会生成一个 GOOGLE_CREDENTIALS_FILE,这是一个 JSON 文档,描述了密钥和其他一些内容。像gcloud-java 这样的客户端可以读取这些文件,如下所示:

    StorageOptions options = StorageOptions.builder().projectId(PROJECT_ID)
        .authCredentials(AuthCredentials.createForJson(
              new FileInputStream(PATH_TO_JSON_KEY))).build();
    Storage service = options.service();
    

    不过,您的代码需要一个 p12 密钥文件。您可以将 JSON 文件中的密钥提取为这种格式,但更简单的方法可能是调用 serviceAccounts.keys.create 并将 serviceAccountPrivateKey 参数设置为 TYPE_PKCS12_FILE

    【讨论】:

    • 谢谢。我使用TYPE_PKCS12_FILE 生成了密钥,但现在我收到java.security.InvalidKeyException: IOException : version mismatch: (supported:00,parsed:03 错误。
    【解决方案2】:

    原来使用serviceAccounts.keys.create生成的私钥字符串的密码是notasecret。以下代码从 API 响应的 privateKeyData 字段中获取 PrivateKey。这个PrivateKey可以用来获取GoogleCredential

    byte[] privKeyBytes = Base64.decodeBase64(privKeyString.getBytes());
    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(new ByteArrayInputStream(privKeyBytes), "notasecret".toCharArray());
    PrivateKey privateKey = (PrivateKey) ks.getKey("privatekey", "notasecret".toCharArray());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-17
      • 2021-04-26
      • 2022-01-19
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      相关资源
      最近更新 更多