Secret.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. namespace components;
  3. use Yii;
  4. use yii\base\Component;
  5. /**
  6. * Class Secret
  7. * @package components
  8. */
  9. class Secret extends Component
  10. {
  11. public $showErrorInfo = true;
  12. private $_contentType = 'application/json';
  13. private $_timeout = 300;
  14. private $_contentMd5 = '';
  15. private $_signatureMethod = 'md5';
  16. private $_signatureVersion = '1.0';
  17. private $_serverSignature = '';
  18. private $_clientSignature = '';
  19. /**
  20. * checkSignature
  21. * @param $client_id
  22. * @param $clientSignature
  23. */
  24. public function checkSignature($client_id, $clientSignature)
  25. {
  26. $this->_clientSignature = $clientSignature;
  27. $cone = $this->findOne($client_id);
  28. if (!$cone)
  29. static::throwError("client id avail.");
  30. $sKey = isset($cone->client_key) ? $cone->client_key : '';
  31. $headers = Yii::$app->request->getHeaders();
  32. if (!$headers)
  33. static::throwError("headers format avail.");
  34. $strVerb = strtoupper($headers->get('verb'));
  35. if (!$strVerb || !in_array(($strVerb), ['POST', 'GET']))
  36. static::throwError("headers verb avail.");
  37. $strMd5 = $headers->get('content-md5');
  38. if (!$this->checkContentMd5($strVerb, $strMd5, Yii::$app->request->getBodyParams()))
  39. static::throwError("headers content md5 avail.");
  40. $strContentType = $headers->get('content-type');
  41. if ($strContentType !== $this->_contentType)
  42. static::throwError("headers content type avail.");
  43. //$strDate = gmdate("D, d M Y H:i:s \G\M\T");
  44. $strDate = $headers->get('date');
  45. $strTime = strtotime($strDate);
  46. if ($strDate == false || $strTime-time() > 0 || time()-$strTime > $this->_timeout)
  47. static::throwError("headers date avail.");
  48. $strSM = $headers->get('signature-method');
  49. if (strtoupper($strSM) != strtoupper($this->_signatureMethod))
  50. static::throwError("headers signature method avail.");
  51. $strSV = $headers->get('signature-version');
  52. if ($strSV !== $this->_signatureVersion)
  53. static::throwError("headers signature version avail.");
  54. $str = "{$strVerb}\n\n{$strMd5}\n{$strContentType}\n{$strDate}\n{$strSM}\n{$strSV}\n\n{$sKey}\n";
  55. $base_sha1 = base64_encode(hash_hmac("sha1", $str, $sKey . '&', true));
  56. $this->_serverSignature = md5($base_sha1);
  57. if ($this->_serverSignature != '' && $this->_serverSignature !== $this->_clientSignature)
  58. static::throwError("Signature verification failed.");
  59. return true;
  60. }
  61. /**
  62. * findOne
  63. * @param $client_id
  64. */
  65. protected function findOne($client_id = false)
  66. {
  67. $model = new \common\models\Client();
  68. return $model::findOne(['client_id' => $client_id]);
  69. }
  70. /**
  71. * checkContentMd5
  72. * @param $verb
  73. * @param $md5
  74. * @param $post
  75. * @return bool
  76. */
  77. protected function checkContentMd5($verb, $md5, $post)
  78. {
  79. if ($verb == 'GET' && $md5 != '')
  80. return false;
  81. if (!is_array($post))
  82. return true;
  83. $s = static::kSortParams($post);
  84. if (!$s)
  85. return true;
  86. $this->_contentMd5 = md5(json_encode($s));
  87. if ( strtolower($md5) != strtolower($this->_contentMd5))
  88. return false;
  89. return true;
  90. }
  91. /**
  92. * kSortParams
  93. * @param $arr
  94. * @return mixed
  95. */
  96. public static function kSortParams($arr)
  97. {
  98. foreach ($arr as $k => $v) {
  99. if ($v === [] || $v === '' || $v === null) {
  100. unset($arr[$k]);
  101. continue;
  102. }
  103. if (is_array($v))
  104. $arr[$k] = static::kSortParams($v);
  105. }
  106. ksort($arr);
  107. return $arr;
  108. }
  109. /**
  110. * throwError
  111. * @param $msg
  112. * @throws \yii\web\UnauthorizedHttpException
  113. */
  114. public function throwError($msg)
  115. {
  116. if ($this->showErrorInfo !== true)
  117. throw new \yii\web\UnauthorizedHttpException('Signature error');
  118. throw new \yii\web\UnauthorizedHttpException($msg);
  119. }
  120. }