使用 PHP 创建 URL 签名 - Amazon CloudFront
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

使用 PHP 创建 URL 签名

运行 PHP 的任何 Web 服务器可使用此 PHP 代码示例,来为私有的 CloudFront 分配创建策略声明和签名。该完整示例使用签名 URL 链接创建一个正常运作的网页,这些链接使用 CloudFront 流播放视频流。您可以从 demo-php.zip 文件下载完整示例。

备注
  • 创建 URL 签名只是使用签名 URL 提供私有内容过程的一部分。有关整个过程的更多信息,请参阅使用签名 URL

  • 还可以通过使用 适用于 PHP 的 Amazon SDK 中的 UrlSigner 类来创建签名 URL。有关更多信息,请参阅 适用于 PHP 的 Amazon SDKAPI 参考中的 Class UrlSigner

以下部分将代码示例细分到各个单独的部分。您可在下方找到完整代码示例

创建 RSA SHA-1 签名

本代码示例执行以下操作:

  • 函数 rsa_sha1_sign 执行哈希操作并签署策略声明。所需的参数是策略语句和私有密钥,该私有密钥对应于分配的可信密钥组中的公有密钥。

  • 接下来,url_safe_base64_encode 函数创建签名 URL 安全版本。

function rsa_sha1_sign($policy, $private_key_filename) { $signature = ""; // load the private key $fp = fopen($private_key_filename, "r"); $priv_key = fread($fp, 8192); fclose($fp); $pkeyid = openssl_get_privatekey($priv_key); // compute signature openssl_sign($policy, $signature, $pkeyid); // free the key from memory openssl_free_key($pkeyid); return $signature; } function url_safe_base64_encode($value) { $encoded = base64_encode($value); // replace unsafe characters +, = and / with // the safe characters -, _ and ~ return str_replace( array('+', '=', '/'), array('-', '_', '~'), $encoded); }

以下代码段使用函数 get_canned_policy_stream_name()get_custom_policy_stream_name() 来创建标准策略和自定义策略。CloudFront 使用这些策略来创建用于流式传输视频的 URL,包括指定过期时间。

然后,您可以使用标准策略或自定义策略来确定如何管理对内容的访问。有关选择哪一项的更多信息,请参阅决定为签名 URL 使用标准策略还是自定义策略部分。

创建标准策略

以下代码示例构建了签名的标准策略声明。

注意

$expires 变量是一个日期/时间戳,必须为整数,而不是字符串。

function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) { // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}'; // the policy contains characters that cannot be part of a URL, so we base64 encode it $encoded_policy = url_safe_base64_encode($canned_policy); // sign the original policy, not the encoded version $signature = rsa_sha1_sign($canned_policy, $private_key_filename); // make the signature safe to be included in a URL $encoded_signature = url_safe_base64_encode($signature); // combine the above into a stream name $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires); // URL-encode the query string characters return $stream_name; }

更多有关标准策略的信息,请参阅 使用标准策略创建签名 URL

创建自定义策略

以下代码示例构建了签名的自定义 策略声明。

function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) { // the policy contains characters that cannot be part of a URL, so we base64 encode it $encoded_policy = url_safe_base64_encode($policy); // sign the original policy, not the encoded version $signature = rsa_sha1_sign($policy, $private_key_filename); // make the signature safe to be included in a URL $encoded_signature = url_safe_base64_encode($signature); // combine the above into a stream name $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null); // URL-encode the query string characters return $stream_name; }

更多有关自定义策略的信息,请参阅 使用自定义策略创建签名 URL

完整代码示例

以下代码示例完整演示了使用 PHP 创建 CloudFront 签名 URL。您可以从 demo-php.zip 文件下载完整示例。

在下面的示例中,您可以修改 $policy Condition 元素,以同时允许 IPv4 和 IPv6 地址范围。有关示例,请参阅《Amazon Simple Storage Service 用户指南》中的在 IAM 策略中使用 IPv6 地址

<?php function rsa_sha1_sign($policy, $private_key_filename) { $signature = ""; // load the private key $fp = fopen($private_key_filename, "r"); $priv_key = fread($fp, 8192); fclose($fp); $pkeyid = openssl_get_privatekey($priv_key); // compute signature openssl_sign($policy, $signature, $pkeyid); // free the key from memory openssl_free_key($pkeyid); return $signature; } function url_safe_base64_encode($value) { $encoded = base64_encode($value); // replace unsafe characters +, = and / with the safe characters -, _ and ~ return str_replace( array('+', '=', '/'), array('-', '_', '~'), $encoded); } function create_stream_name($stream, $policy, $signature, $key_pair_id, $expires) { $result = $stream; // if the stream already contains query parameters, attach the new query parameters to the end // otherwise, add the query parameters $separator = strpos($stream, '?') == FALSE ? '?' : '&'; // the presence of an expires time means we're using a canned policy if($expires) { $result .= $separator . "Expires=" . $expires . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id; } // not using a canned policy, include the policy itself in the stream name else { $result .= $separator . "Policy=" . $policy . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id; } // new lines would break us, so remove them return str_replace('\n', '', $result); } function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) { // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}'; // the policy contains characters that cannot be part of a URL, so we base64 encode it $encoded_policy = url_safe_base64_encode($canned_policy); // sign the original policy, not the encoded version $signature = rsa_sha1_sign($canned_policy, $private_key_filename); // make the signature safe to be included in a URL $encoded_signature = url_safe_base64_encode($signature); // combine the above into a stream name $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires); // URL-encode the query string characters return $stream_name; } function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) { // the policy contains characters that cannot be part of a URL, so we base64 encode it $encoded_policy = url_safe_base64_encode($policy); // sign the original policy, not the encoded version $signature = rsa_sha1_sign($policy, $private_key_filename); // make the signature safe to be included in a URL $encoded_signature = url_safe_base64_encode($signature); // combine the above into a stream name $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null); // URL-encode the query string characters return $stream_name; } // Path to your private key. Be very careful that this file is not accessible // from the web! $private_key_filename = '/home/test/secure/example-priv-key.pem'; $key_pair_id = 'K2JCJMDEHXQW5F'; // Make sure you have "Restrict viewer access" enabled on this path behaviour and using the above Trusted key groups (recommended). $video_path = 'https://example.com/secure/example.mp4'; $expires = time() + 300; // 5 min from now $canned_policy_stream_name = get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires); // Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345") $client_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; $policy = '{'. '"Statement":['. '{'. '"Resource":"'. $video_path . '",'. '"Condition":{'. '"IpAddress":{"AWS:SourceIp":"' . $client_ip . '/32"},'. '"DateLessThan":{"AWS:EpochTime":' . $expires . '}'. '}'. '}'. ']' . '}'; $custom_policy_stream_name = get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy); ?> <html> <head> <title>CloudFront</title> </head> <body> <h1>Amazon CloudFront</h1> <h2>Canned Policy</h2> <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?></h3> <br /> <div id='canned'>The canned policy video will be here: <br> <video width="640" height="360" autoplay muted controls> <source src="<?php echo $canned_policy_stream_name; ?>" type="video/mp4"> Your browser does not support the video tag. </video> </div> <h2>Custom Policy</h2> <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h3> <div id='custom'>The custom policy video will be here: <br> <video width="640" height="360" autoplay muted controls> <source src="<?php echo $custom_policy_stream_name; ?>" type="video/mp4"> Your browser does not support the video tag. </video> </div> </body> </html>

有关更多 URL 签名示例,请参阅以下主题:

您可以不使用签名 URL 来创建签名,而是使用签名 Cookie。有关更多信息,请参阅 使用 PHP 创建签名 Cookie