我正在尝试使用签名网址作为身份验证,直接通过javascript将图片的base64数据上传到Google存储空间,这显然可以做到。
根据developers.google.com/storage/docs/reference-methods#putobject,只需要设置六个标头即可实现此功能。同样对于标题'授权',我试图在这里使用最后一个选项:
developers.google.com/storage/docs/reference-headers#authorization
哪个是'签名'developers.google.com/storage/docs/authentication#service_accounts
我唯一想要使用PHP的是获取签名。以下是我一直努力工作的结果。
PHP& JS页面/代码
<?php
$theDate = Date(DATE_RFC822);
function signedURL( $filename, $bucket, $method = 'PUT' ) {
$signature = "";
$duration = 30;
$emailID = "980000000000-ytyertyr@developer.gserviceaccount.com";
$certs = array();
$priv_key = file_get_contents("9999999999999999999999999999-privatekey.p12");
if (!openssl_pkcs12_read($priv_key, $certs, 'notasecret')) { echo "Unable to parse the p12 file. OpenSSL error: " . openssl_error_string(); exit(); }
$expires = time() + $duration;
$to_sign = ( $method . "\n\n\n" . $expires . "\n" . "/" . $bucket . "/" . $filename );
$RSAPrivateKey = openssl_pkey_get_private($certs["pkey"]);
if (!openssl_sign( $to_sign, $signature, $RSAPrivateKey, 'sha256' ))
{
error_log( 'openssl_sign failed!' );
$signature = 'failed';
} else {
$signature = urlencode( base64_encode( $signature ) );
}
return (
'http://storage.googleapis.com/' . $bucket . '/' . $filename . '?GoogleAccessId=' . $emailID . '&Expires=' . $expires . '&Signature=' . $signature
);
openssl_free_key($RSAPrivateKey);
}
?>
<script>
var base64img = 'data:image/png;base64,AAABAAIAICA....snip...A';
var xhr = new XMLHttpRequest();
//PUT test - PUT status "(Canceled)" - OPTION status 200 (OK)
xhr.open("PUT", "<?php echo signedURL('test.png', 'mybucket'); ?>");
//xhr.setRequestHeader("Content-type", "image/png");
xhr.setRequestHeader("x-goog-acl", "public-read"); //try to set public read on file
xhr.setRequestHeader("Content-Length", base64img.length); // Chrome throws error (Refused to set unsafe header "Content-Length" )
xhr.send( base64img );
//GET test.txt temp file - working and returning 200 status (signing must be working ?)
/*
xhr.open("GET", "<?php echo signedURL('test.txt', 'mybucket', 'GET'); ?>");
xhr.send();
*/
//
</script>
Cors xml(似乎很好) - 我只在测试时设置了通配符,缓存/最大时间很短
<?xml version="1.0" ?>
<CorsConfig>
<Cors>
<Origins>
<Origin>*</Origin>
</Origins>
<Methods>
<Method>GET</Method>
<Method>HEAD</Method>
<Method>OPTIONS</Method>
<Method>PUT</Method>
</Methods>
<ResponseHeaders>
<ResponseHeader>accept-encoding</ResponseHeader>
<ResponseHeader>cache-control</ResponseHeader>
<ResponseHeader>content-length</ResponseHeader>
<ResponseHeader>content-type</ResponseHeader>
<ResponseHeader>expect</ResponseHeader>
<ResponseHeader>if-modified-since</ResponseHeader>
<ResponseHeader>origin</ResponseHeader>
<ResponseHeader>range</ResponseHeader>
<ResponseHeader>referer</ResponseHeader>
<ResponseHeader>x-goog-acl</ResponseHeader>
<ResponseHeader>x-goog-api-version</ResponseHeader>
</ResponseHeaders>
<MaxAgeSec>900</MaxAgeSec>
</Cors>
</CorsConfig>
我已经在文件上测试了GET方法,现在又恢复了200状态(\ n \ n - 修复)
更新
在Firefox中,它确实会返回403,与Chrome不同。
答案 0 :(得分:3)
所以以下几行很奇怪,因为使用OA将OAuth和PUT混合签名的URL:
# This looks like a PUT to signed URL
xhr.open("PUT", '<?php echo signedURL('imgfile.png','PUT',30,'mybucketname'); ?>', true);
# But multipart requires POST
xhr.setRequestHeader("Content-type", "multipart/form-data; boundary="+boundary);
# And here's a second form of authorization
xhr.setRequestHeader("Authorization", "OAuth <?php echo $signature; ?>");
multipart/form-data
上传需要POST
动词,适用于html表单:Google Cloud Storage : PUT Object vs POST Object to upload file.?。
只要您在XMLHttpRequest中发送自定义标头,我建议您使用 {em> <{em> OAuth credentials {/ 1>}使用PUT
:
xhr.open("PUT", "https://storage.googleapis.com/mybucketname/imgfile.png");
xhr.setRequestHeader("Authorization", "OAuth Bearer 1234567abcdefg");
xhr.setRequestHeader("Content-Length", raw_img_bytes.length);
xhr.send(raw_img_bytes);
或 a signed url:
xhr.open("PUT", "https://storage.googleapis.com/mybucketname/imgfile.png?" +
"GoogleAccessId=1234567890123@developer.gserviceaccount.com&" +
"Expires=136891473&" +
"Signature=BClz9e...WvPcwN%2BmWBPqwg...sQI8IQi1493mw%3D");
xhr.setRequestHeader("Content-Length", raw_img_bytes.length);
xhr.send(raw_img_bytres);
答案 1 :(得分:0)
我gess你的Content-Type是已知的(比如Content-Type:video / mp4)?尝试上传未知扩展名的文件。对我来说,PUT正在这种情况下工作,而不是当Content-Type不为空时...... 我不明白为什么......