Google app engine 将clientsecret转换为私钥

Google app engine 将clientsecret转换为私钥,google-app-engine,sha256,google-cloud-storage,Google App Engine,Sha256,Google Cloud Storage,我在AppEngine中使用Google云存储,我试图使用POST表单将文件上传到GCS。我遇到的问题是签署政策文件所需的步骤。我可以很容易地获取client_secret,它是API控制台提供给我的client_secrets.json中的一个字符串。但是,为了创建签名,我需要将该字符串转换为PrivateKey对象。我的代码是这样的: //create the policy document and encode it String policyDocument = ... //omitt

我在AppEngine中使用Google云存储,我试图使用POST表单将文件上传到GCS。我遇到的问题是签署政策文件所需的步骤。我可以很容易地获取client_secret,它是API控制台提供给我的
client_secrets.json
中的一个字符串。但是,为了创建签名,我需要将该字符串转换为
PrivateKey
对象。我的代码是这样的:

//create the policy document and encode it
String policyDocument = ...  //omitted for brevity
String encodedPolicy = Base64.encodeString(policyDocument);

//sign using SHA256 with RSA
String secretKey = ... //I fetch this from client_secrets.json
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(secretKey); //THIS IS THE PROBLEM!  
sig.update(encodedPolicy.getBytes("UTF-8"));        
String signature = new String(Base64.encode(sig.sign()));

//put the values in the request attributes so we can fetch them from a JSP
req.setAttribute("policy", encodedPolicy);
req.setAttribute("signature", signature);
如上所述,我的问题就在这条线上

sig.initSign(secretKey); //THIS IS THE PROBLEM!  
secretKey
是一个字符串
Signature.initSign()
需要一个
PrivateKey
,或者它的一个后代对象。如何将
client_secrets.json
中的字符串转换为可以传递
Signature.initSign
的PrivateKey(或派生)对象

任何帮助都将不胜感激。谢谢

好的,我现在就在这里。我尝试了下面的建议,所有文档都敦促我使用从Google API控制台下载的client_secrets.json文件中的client_secret,而不是服务帐户。此外,我试图构建一个用户上传的示例,而不是一个服务帐户

我在另一页上找到以下代码:

public static String signPolicyDocument(String policyDocument, String secret) {     
try {
        Mac mac = Mac.getInstance("HmacSHA256");
        byte[] secretBytes = secret.getBytes();
        SecretKeySpec signingKey = new SecretKeySpec(secretBytes, "HmacSHA256");
        mac.init(signingKey);
        byte[] signedSecretBytes = mac.doFinal(policyDocument.getBytes());          
        return new String(Base64.encode(signedSecretBytes));
    } catch (InvalidKeyException e) {
        throw new RuntimeException(e);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
在我提交结果表之前,它会一直帮助我完成整个过程。然后我得到了如下的回应:

The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

它在寻找什么样的签名方法?

我认为您需要这样做:

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
sig.initSign(privateKey);

keyBytes
变量应包含一个
byte[]
数组。要从Appengine将文件上载到GCS,可以使用blobstore Api。按照中描述的步骤操作。优点是你不必担心钥匙,代码也简单得多。

这个问题的最终答案就像战争游戏的结论一样。正如WOPR所说,“一个奇怪的游戏……取胜的唯一途径就是不玩。”避免签署和政策文件以及所有那些废话,使用blobstore

(见此:)

它很容易实现;创建临时blobstore上载URL时,如下所示:

    //open the blobstore service and create the upload url
    BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();        
    String uploadUrl = bs.createUploadUrl("/display",
            UploadOptions.Builder.withGoogleStorageBucketName(bucket));

这种方法的缺点是对象名将是一个您无法识别的字符串。您可以打开blobstore查看器并在blobstore中按文件名查看对象,但在GCS中,其对象名将为gobbledygook。(可能是散列?随机分配的ID)?

您正在使用App Engine吗?这个问题没有提到,但它被贴上了这样的标签。我在AppEngine工作。我编辑了这篇文章来反映这个事实。谢谢你的回复。我发现了几个问题。首先:Google App Engine的Java运行时环境不支持sun.misc.base64解码器。所以我尝试用以下内容替换它:byte[]encodedKey=Base64.decode(key64);那没用;它抛出“Base64编码数据中的非法字符”,因此我省略了解码步骤;我只是简单地将密钥直接传递到keyspec中。结果是java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:IOException:Detect premature EOF如果你是对的,你应该使用
Base64.decode
。您是否使用client_secrets.json的“client_secret”字段?它应该是有效的base64。是的,我使用的是client_secrets.json中的client_secret。在一个调试窗口中,我验证了我从json中提取的客户机密码与GoogleAPI控制台上的客户机密码完全匹配。当我传入client_secret时,它
Base64.decode
仍然抛出异常。为了确保这一点,我生成了一个新的secret并更新了client_secrets.json。现在,
Base64.decode
执行时不会出现异常,我可以将结果传递到keySpec中。但是当我到达
keyFactory.generatePrivate(keypec)时我得到以下错误:
java.security.InvalidKeyException:IOException:Detect premature EOF
如果有办法在代码中指定将对象保存到GCS时使用的对象名称,那么这种方法就完美了。有人知道怎么做吗?还在改进这个方法。我找到的一个可能的解决方案是这样做:继续改进这种方法。我找到的一个可能的解决办法是1。上传文件2。捕获gobbledygook文件名3。将gobbledygook文件名复制到您想要的任何文件名4。删除具有gobbledygook名称的文件以进行复制,您要做的是发出一个添加了x-goog-copy-source头的PUT请求:您现在可能已经知道这一点,但为了子孙后代,您可以在上载处理程序中获得一个FileInfo对象,该对象上有gs_对象_名称。。。