使用 PHP 创建 URL 签名 - Amazon CloudFront

使用 PHP 创建 URL 签名

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

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

注意

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

示例: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); }

示例:创建标准策略

以下代码示例构建了签名的标准策略声明。更多有关标准策略的信息,请参阅 使用标准策略创建签名 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 . '}}}]}'; // sign the canned policy $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 to work around a flash player bug return encode_query_params($stream_name); }

示例:创建自定义策略

以下代码示例构建了签名的自定义 策略声明。更多有关自定义策略的信息,请参阅 使用自定义策略创建签名 URL

function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) { // sign the policy $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 to work around a flash player bug return encode_query_params($stream_name); }

完整代码示例

以下代码示例完整演示了使用 PHP 创建 CloudFront 签名 URL。您可以在下面下载此完整示例:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/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 .= $path . $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 .= $path . $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 encode_query_params($stream_name) { // Adobe Flash Player has trouble with query parameters being passed into it, // so replace the bad characters with their URL-encoded forms return str_replace( array('?', '=', '&'), array('%3F', '%3D', '%26'), $stream_name); } 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 to support Flash Player return encode_query_params($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 to support Flash Player return encode_query_params($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'; $video_path = '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); $client_ip = $_SERVER['REMOTE_ADDR']; $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> <script type='text/javascript' src='https://example.cloudfront.net/player/swfobject.js'></script> </head> <body> <h1>Amazon CloudFront</h1> <h2>Canned Policy</h2> <h3>Expires at <?= gmdate('Y-m-d H:i:s T', $expires) ?></h3> <br /> <div id='canned'>The canned policy video will be here</div> <h2>Custom Policy</h2> <h3>Expires at <?= gmdate('Y-m-d H:i:s T', $expires) ?> only viewable by IP <?= $client_ip ?></h3> <div id='custom'>The custom policy video will be here</div> <!-- ************** Have to update the player.swf path to a real JWPlayer instance. The fake one means that external people cannot watch the video right now --> <script type='text/javascript'> var so_canned = new SWFObject('https://files.example.com/player.swf','mpl','640','360','9'); so_canned.addParam('allowfullscreen','true'); so_canned.addParam('allowscriptaccess','always'); so_canned.addParam('wmode','opaque'); so_canned.addVariable('file','<?= $canned_policy_stream_name ?>'); so_canned.addVariable('streamer','rtmp://example.cloudfront.net/cfx/st'); so_canned.write('canned'); var so_custom = new SWFObject('https://files.example.com/player.swf','mpl','640','360','9'); so_custom.addParam('allowfullscreen','true'); so_custom.addParam('allowscriptaccess','always'); so_custom.addParam('wmode','opaque'); so_custom.addVariable('file','<?= $custom_policy_stream_name ?>'); so_custom.addVariable('streamer','rtmp://example.cloudfront.net/cfx/st'); so_custom.write('custom'); </script> </body> </html>

另请参阅: