使用 GoogleCloudEndpoints 访问 GoogleCloudStorage

Access GoogleCloudStorage using GoogleCloudEndpoints

我正在处理这个项目,我正在使用 Google-App-Engine 后端通过 Google-Cloud-Endpoints 连接到 Android 应用程序。对于 Google-Cloud-Datastore 访问,我正在使用 Objectify,一切正常。

现在我决定添加将图像上传到 Google-Cloud-Storage 的功能,但我找不到关于如何使用 Google-Cloud-Endpoints 执行此操作的明确解释设置。

我找到了如何将 Google-Cloud-Storage 与 Google-App-Engine 一起使用的以下说明: https://cloud.google.com/appengine/docs/java/googlecloudstorageclient/app-engine-cloud-storage-sample

但文章没有将其添加到端点 Api,而是编写了一个额外的 servlet。

此外,我发现 Android 的 upload/download 示例:

github.com /thorrism/GoogleCloudExample

遗憾的是,这是使用 Google 云存储 API 直接访问 Google-云存储,您需要将 P12 文件添加到资产文件夹,这似乎不安全。

我的 Google-App-Engine 代码如下所示:

@Api(
    name = "example",
    version = "v1", 
    scopes = { Constants.EMAIL_SCOPE }, 
    clientIds = { Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID }, 
    audiences = {Constants.ANDROID_AUDIENCE},
    description = "API for the Example Backend application."

)

public class ExampleApi{

@ApiMethod(name = "doSomething", path = "dosomething", httpMethod = HttpMethod.POST)
public String doSomething(@Named("text") String text){

  TestEntity test = new TestEntity(text);

   ofy().save().entity(test).now();

   return  test;

}

上传后,我生成了端点客户端库并将其导入到我的 android 项目中。

然后我从 Android 调用端点,就像这里解释的那样:

https://cloud.google.com/appengine/docs/java/endpoints/calling-from-android#creating_the_service_object

public static com.appspot.******.example.Example buildServiceHandler(Context context, String email) {
    GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(
            context, AppConstants.AUDIENCE);
    credential.setSelectedAccountName(email);

     com.appspot.******.example.Example.Builder builder  = new  com.appspot.******.example.Example.Builder(
            AppConstants.HTTP_TRANSPORT,
            AppConstants.JSON_FACTORY, null);
    builder.setApplicationName("example-server");
    return builder.build();
}

sApiServiceHandler = buildServiceHandlerWithAuth(context,email);

每个Api-我这样调用的方法:

com.appspot.******.example.Example.DoSomething doSomething = sApiServiceHandler.doSomething(someString);
doSomething.execute();

所有这些工作正常,但仅适用于 storing/receiving 数据存储实体。我如何使用 Google Cloud Endpoints 设置将 uploading/downloading 文件传输到 Google Cloud Storage? 是否可以使用已经构建的 ServiceHandler 通过 Endpoints 将带有我的图像数据的 POST 发送到 UploadServlet ? 是否可以从端点方法调用 servlet?我应该如何将 Post 发送到 Servlet,我将如何进行身份验证?

如有任何帮助或建议,我们将不胜感激!

有多种方法可以做到这一点,但最推荐的方法是使用 Signed URLs,这样您的 Android 应用程序就可以将文件安全地直接上传到 Google 云存储,无需通过您的 Endpoints 后端。基本流程是:

1) 创建一个 Endpoints 方法,将 creates a new signed URL 和 returns 发送到 Android 客户端。在服务器上签署 URL 仍然需要 P12 密钥,但存储在 App Engine 上,而不是在客户端上,因此是安全的。尝试为 URL 使用较短的到期时间,例如不超过 5 分钟。

2) Android 客户端 upload the file directly to the signed URL, as you would doing a normal HTTP PUT to the Cloud Storage XML API to upload a file (resumable uploads with the JSON API 也受支持,但不在此处介绍)。

您的端点方法可能如下所示:

@ApiMethod(name = "getUploadUrl", path = "getuploadurl", httpMethod = HttpMethod.GET)
public MyApiResponse getUploadUrl(@Named("fileName") String fileName
                                  @Named("contentType" String contentType)
{
        String stringToSign
            = "PUT\n" + contentType
            + "\n" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS + "\n"
            + YOUR_GCS_BUCKET + "/" + fileName;

        // Load P12 key
        FileInputStream fileInputStream = new FileInputStream(PATH_TO_P12_KEY);
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(fileInputStream, password);
        PrivateKey key = keyStore.getKey(privatekey", YOUR_P12_KEY_PASSWORD);

        // Get signature
        Signature signer = Signature.getInstance("SHA256withRSA");
        signer.initSign(key);
        signer.update(stringToSign.getBytes("UTF-8"));
        byte[] rawSignature = signer.sign();
        String signature = new String(Base64.encodeBase64(rawSignature, false), "UTF-8");

        // Construct signed url
        String url
            = "http://storage.googleapis.com/" + YOUR_GCS_BUCKET + fileName
            + "?GoogleAccessId=" + P12_KEY_SERVICE_ACCOUNT_CLIENT_ID
            + "&Expires=" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS
            + "&Signature=" + URLEncoder.encode(signature, "UTF-8");

        // Endpoints doesn't let you return 'String' directly
        MyApiResponse response = new MyApiResponse();
        response.setString(url);
        return response;
}

在Android这边,你可以使用这样的方法:

// Get the upload URL from the API
getUploadUrl = sApiServiceHandler.getUploadUrl(fileName, contentType);
MyApiResponse response = getUploadUrl.execute();
String uploadUrl = response.getString();

// Open connection to GCS
URL url = new URL(uploadUrl);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setDoOutput(true);
httpConnection.setRequestMethod("PUT");
httpConnection.setRequestProperty("Content-Type", contentType);

// Write file data
OutputStreamWriter out = new OutputStreamWriter(httpConnection.getOutputStream());
out.write(fileData);
out.flush();

// Get response, check status code etc.
InputStreamReader in = new InputStreamReader(httpConnection.getInputStream());
// ...

(免责声明:我只是在文本编辑器中随意输入代码,并没有实际测试它,但它应该足以让您大致了解。)