使用 PHP 为 Google 云存储使用 JWT 签名 URL
Signing URLs with JWT for Google Cloud Storage using PHP
我刚刚开始将我的 Google 云存储代码从 API 1.0 版升级到 2.0 版,但遇到了一些麻烦。
在 1.0 版中,我使用 Signed URLs 取得了巨大的成功,使用的是 .p12 文件。但是,在新版本中已弃用,我必须改用 Firebase/php-jwt,使用 JSON 文件。
问题是它无法正常工作,我收到错误消息:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
<StringToSign>PUT
image/png
1483626991
/myBucket/folder/test.PNG</StringToSign></Error>
这是用于签名的简化代码。
$string = ($method . "\n" .
$contentMd5 . "\n" .
$contentType . "\n" .
$expiration . "\n" .
$file);
$signedURL = base64_encode(Firebase\JWT\JWT::encode($string,
file_get_contents($credentialsFilePath)));
收到签名URL后,我用正确的数据构建了一个URL。我从 1.0 和 2.0 更改的唯一部分是您签署 URL 的部分。此外,我检查了响应的 "StringToSign"-field 中的字符串是否与我正在签名的字符串完全相同。
在 1.0 版中,我这样签署 URL:
$signedURL = base64_encode((new Google_Signer_P12(
file_get_contents($p12FilePath),
'notasecret'
))->sign($string));
所有这一切让我相信我唱的内容是正确的,但使用 JWT 功能的方式不对。还有其他人这样做吗?你是怎么做到的?
如果有趣的话,这是我构建的 URL(适用于 1.0):
$returnArr['url'] = "https://{$bucket}.commondatastorage.googleapis.com/"
. $prefix . '/' . rawurlencode($file)
. "?GoogleAccessId=" . rawurlencode($serviceEmail)
. "&Expires={$expiration}"
. "&Signature=" . rawurlencode($signature);
查看源代码 JWT library 我首先想到的是,您的负载应该是数组或对象,而不是字符串... “JSON 网络令牌”。
* @param object|array $payload PHP object or array
public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
其次,貌似你是双base64编码吧...base128? :)
encode
的return值应该是三个Base64url字符串拼接在一起,所以应该不需要重复了。
我会试一试:
$payload = ['HTTP_Verb' => $method,
'Content_MD5' => $contentMd5,
'Content_Type' => $contentType,
'Expiration' => $expiration,
'Canonicalized_Resource' => $file];
$key = file_get_contents($credentialsFilePath);
$signedURL = Firebase\JWT\JWT::encode($payload, $key); //think base64_encode here is redundant.
参考:Overview of Signed URLs page。他们肯定不会在这些文档中很好地解释事情。
我假设您看过 SDK?
如果您想走字符串路线,您需要使用 SHA256 的 RSA 签名进行签名...opensssl_sign
或者也可能更容易依靠 Google's PHP SDKs?
稍后...
好的,决定测试一下。看到 Google Cloud 进行了免费试用。安装 gsutil
,阅读了一堆文档。如果我理解这种 JWT 方法,该死的。如果有人甚至可以提供有关该主题的文档,请分享。
此代码有效:
<?php
$method = 'GET';
$expires = '1503532674';
$container = '/example-bucket/cat.jpeg';
$payload = "{$method}\n\n\n{$expires}\n{$container}";
//assume you have this 'json' formatted key too? Otherwise just load the private key file as is.
$key = file_get_contents('~/oas_private_key.json');
$key = json_decode($key, true);
$key = $key['private_key'];
//if sucessful the encypted string is assigned to $signature
openssl_sign($payload, $signature, $key, OPENSSL_ALGO_SHA256);
$signature = urlencode(base64_encode($signature));
die("https://storage.googleapis.com/{$container}?GoogleAccessId=oastest@foo.iam.gserviceaccount.com&Expires={$expires}&Signature={$signature}");
终于没有"SignatureDoesNotMatch"错误了!我个人会使用 SDK。一点初始化,你可以做如下的事情:
$url = $object->signedUrl(new Timestamp(new DateTime('tomorrow')), [
'method' => 'PUT'
]);
也方便以后升级。
我刚刚开始将我的 Google 云存储代码从 API 1.0 版升级到 2.0 版,但遇到了一些麻烦。
在 1.0 版中,我使用 Signed URLs 取得了巨大的成功,使用的是 .p12 文件。但是,在新版本中已弃用,我必须改用 Firebase/php-jwt,使用 JSON 文件。
问题是它无法正常工作,我收到错误消息:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
<StringToSign>PUT
image/png
1483626991
/myBucket/folder/test.PNG</StringToSign></Error>
这是用于签名的简化代码。
$string = ($method . "\n" .
$contentMd5 . "\n" .
$contentType . "\n" .
$expiration . "\n" .
$file);
$signedURL = base64_encode(Firebase\JWT\JWT::encode($string,
file_get_contents($credentialsFilePath)));
收到签名URL后,我用正确的数据构建了一个URL。我从 1.0 和 2.0 更改的唯一部分是您签署 URL 的部分。此外,我检查了响应的 "StringToSign"-field 中的字符串是否与我正在签名的字符串完全相同。
在 1.0 版中,我这样签署 URL:
$signedURL = base64_encode((new Google_Signer_P12(
file_get_contents($p12FilePath),
'notasecret'
))->sign($string));
所有这一切让我相信我唱的内容是正确的,但使用 JWT 功能的方式不对。还有其他人这样做吗?你是怎么做到的?
如果有趣的话,这是我构建的 URL(适用于 1.0):
$returnArr['url'] = "https://{$bucket}.commondatastorage.googleapis.com/"
. $prefix . '/' . rawurlencode($file)
. "?GoogleAccessId=" . rawurlencode($serviceEmail)
. "&Expires={$expiration}"
. "&Signature=" . rawurlencode($signature);
查看源代码 JWT library 我首先想到的是,您的负载应该是数组或对象,而不是字符串... “JSON 网络令牌”。
* @param object|array $payload PHP object or array
public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
其次,貌似你是双base64编码吧...base128? :)
encode
的return值应该是三个Base64url字符串拼接在一起,所以应该不需要重复了。
我会试一试:
$payload = ['HTTP_Verb' => $method,
'Content_MD5' => $contentMd5,
'Content_Type' => $contentType,
'Expiration' => $expiration,
'Canonicalized_Resource' => $file];
$key = file_get_contents($credentialsFilePath);
$signedURL = Firebase\JWT\JWT::encode($payload, $key); //think base64_encode here is redundant.
参考:Overview of Signed URLs page。他们肯定不会在这些文档中很好地解释事情。 我假设您看过 SDK?
如果您想走字符串路线,您需要使用 SHA256 的 RSA 签名进行签名...opensssl_sign
或者也可能更容易依靠 Google's PHP SDKs?
稍后...
好的,决定测试一下。看到 Google Cloud 进行了免费试用。安装 gsutil
,阅读了一堆文档。如果我理解这种 JWT 方法,该死的。如果有人甚至可以提供有关该主题的文档,请分享。
此代码有效:
<?php
$method = 'GET';
$expires = '1503532674';
$container = '/example-bucket/cat.jpeg';
$payload = "{$method}\n\n\n{$expires}\n{$container}";
//assume you have this 'json' formatted key too? Otherwise just load the private key file as is.
$key = file_get_contents('~/oas_private_key.json');
$key = json_decode($key, true);
$key = $key['private_key'];
//if sucessful the encypted string is assigned to $signature
openssl_sign($payload, $signature, $key, OPENSSL_ALGO_SHA256);
$signature = urlencode(base64_encode($signature));
die("https://storage.googleapis.com/{$container}?GoogleAccessId=oastest@foo.iam.gserviceaccount.com&Expires={$expires}&Signature={$signature}");
终于没有"SignatureDoesNotMatch"错误了!我个人会使用 SDK。一点初始化,你可以做如下的事情:
$url = $object->signedUrl(new Timestamp(new DateTime('tomorrow')), [
'method' => 'PUT'
]);
也方便以后升级。