Auth.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace Qiniu;
  3. use Qiniu\Http\Header;
  4. use Qiniu\Zone;
  5. final class Auth
  6. {
  7. private $accessKey;
  8. private $secretKey;
  9. public $options;
  10. public function __construct($accessKey, $secretKey, $options = null)
  11. {
  12. $this->accessKey = $accessKey;
  13. $this->secretKey = $secretKey;
  14. $defaultOptions = array(
  15. 'disableQiniuTimestampSignature' => null
  16. );
  17. if ($options == null) {
  18. $options = $defaultOptions;
  19. }
  20. $this->options = array_merge($defaultOptions, $options);
  21. }
  22. public function getAccessKey()
  23. {
  24. return $this->accessKey;
  25. }
  26. public function sign($data)
  27. {
  28. $hmac = hash_hmac('sha1', $data, $this->secretKey, true);
  29. return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac);
  30. }
  31. public function signWithData($data)
  32. {
  33. $encodedData = \Qiniu\base64_urlSafeEncode($data);
  34. return $this->sign($encodedData) . ':' . $encodedData;
  35. }
  36. public function signRequest($urlString, $body, $contentType = null)
  37. {
  38. $url = parse_url($urlString);
  39. $data = '';
  40. if (array_key_exists('path', $url)) {
  41. $data = $url['path'];
  42. }
  43. if (array_key_exists('query', $url)) {
  44. $data .= '?' . $url['query'];
  45. }
  46. $data .= "\n";
  47. if ($body !== null && $contentType === 'application/x-www-form-urlencoded') {
  48. $data .= $body;
  49. }
  50. return $this->sign($data);
  51. }
  52. /**
  53. * @param string $urlString
  54. * @param string $method
  55. * @param string $body
  56. * @param null|Header $headers
  57. */
  58. public function signQiniuAuthorization($urlString, $method = "GET", $body = "", $headers = null)
  59. {
  60. $url = parse_url($urlString);
  61. if (!$url) {
  62. return array(null, new \Exception("parse_url error"));
  63. }
  64. // append method, path and query
  65. if ($method === "") {
  66. $data = "GET ";
  67. } else {
  68. $data = $method . " ";
  69. }
  70. if (isset($url["path"])) {
  71. $data .= $url["path"];
  72. }
  73. if (isset($url["query"])) {
  74. $data .= "?" . $url["query"];
  75. }
  76. // append Host
  77. $data .= "\n";
  78. $data .= "Host: ";
  79. if (isset($url["host"])) {
  80. $data .= $url["host"];
  81. }
  82. if (isset($url["port"]) && $url["port"] > 0) {
  83. $data .= ":" . $url["port"];
  84. }
  85. // try append content type
  86. if ($headers != null && isset($headers["Content-Type"])) {
  87. // append content type
  88. $data .= "\n";
  89. $data .= "Content-Type: " . $headers["Content-Type"];
  90. }
  91. // try append xQiniuHeaders
  92. if ($headers != null) {
  93. $headerLines = array();
  94. $keyPrefix = "X-Qiniu-";
  95. foreach ($headers as $k => $v) {
  96. if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) {
  97. array_push(
  98. $headerLines,
  99. $k . ": " . $v
  100. );
  101. }
  102. }
  103. if (count($headerLines) > 0) {
  104. $data .= "\n";
  105. sort($headerLines);
  106. $data .= implode("\n", $headerLines);
  107. }
  108. }
  109. // append body
  110. $data .= "\n\n";
  111. if (!is_null($body)
  112. && strlen($body) > 0
  113. && isset($headers["Content-Type"])
  114. && $headers["Content-Type"] != "application/octet-stream"
  115. ) {
  116. $data .= $body;
  117. }
  118. return array($this->sign($data), null);
  119. }
  120. public function verifyCallback($contentType, $originAuthorization, $url, $body)
  121. {
  122. $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
  123. return $originAuthorization === $authorization;
  124. }
  125. public function privateDownloadUrl($baseUrl, $expires = 3600)
  126. {
  127. $deadline = time() + $expires;
  128. $pos = strpos($baseUrl, '?');
  129. if ($pos !== false) {
  130. $baseUrl .= '&e=';
  131. } else {
  132. $baseUrl .= '?e=';
  133. }
  134. $baseUrl .= $deadline;
  135. $token = $this->sign($baseUrl);
  136. return "$baseUrl&token=$token";
  137. }
  138. public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true)
  139. {
  140. $deadline = time() + $expires;
  141. $scope = $bucket;
  142. if ($key !== null) {
  143. $scope .= ':' . $key;
  144. }
  145. $args = self::copyPolicy($args, $policy, $strictPolicy);
  146. $args['scope'] = $scope;
  147. $args['deadline'] = $deadline;
  148. $b = json_encode($args);
  149. return $this->signWithData($b);
  150. }
  151. /**
  152. *上传策略,参数规格详见
  153. *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
  154. */
  155. private static $policyFields = array(
  156. 'callbackUrl',
  157. 'callbackBody',
  158. 'callbackHost',
  159. 'callbackBodyType',
  160. 'callbackFetchKey',
  161. 'returnUrl',
  162. 'returnBody',
  163. 'endUser',
  164. 'saveKey',
  165. 'forceSaveKey',
  166. 'insertOnly',
  167. 'detectMime',
  168. 'mimeLimit',
  169. 'fsizeMin',
  170. 'fsizeLimit',
  171. 'persistentOps',
  172. 'persistentNotifyUrl',
  173. 'persistentPipeline',
  174. 'deleteAfterDays',
  175. 'fileType',
  176. 'isPrefixalScope',
  177. );
  178. private static function copyPolicy(&$policy, $originPolicy, $strictPolicy)
  179. {
  180. if ($originPolicy === null) {
  181. return array();
  182. }
  183. foreach ($originPolicy as $key => $value) {
  184. if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) {
  185. $policy[$key] = $value;
  186. }
  187. }
  188. return $policy;
  189. }
  190. public function authorization($url, $body = null, $contentType = null)
  191. {
  192. $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
  193. return array('Authorization' => $authorization);
  194. }
  195. public function authorizationV2($url, $method, $body = null, $contentType = null)
  196. {
  197. $headers = new Header();
  198. $result = array();
  199. if ($contentType != null) {
  200. $headers['Content-Type'] = $contentType;
  201. $result['Content-Type'] = $contentType;
  202. }
  203. $signDate = gmdate('Ymd\THis\Z', time());
  204. if ($this->options['disableQiniuTimestampSignature'] !== null) {
  205. if (!$this->options['disableQiniuTimestampSignature']) {
  206. $headers['X-Qiniu-Date'] = $signDate;
  207. $result['X-Qiniu-Date'] = $signDate;
  208. }
  209. } elseif (getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) {
  210. if (strtolower(getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) !== "true") {
  211. $headers['X-Qiniu-Date'] = $signDate;
  212. $result['X-Qiniu-Date'] = $signDate;
  213. }
  214. } else {
  215. $headers['X-Qiniu-Date'] = $signDate;
  216. $result['X-Qiniu-Date'] = $signDate;
  217. }
  218. list($sign) = $this->signQiniuAuthorization($url, $method, $body, $headers);
  219. $result['Authorization'] = 'Qiniu ' . $sign;
  220. return $result;
  221. }
  222. }