Controller.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <?php
  2. /**
  3. * Controller is the customized base controller class.
  4. * All controller classes for this application should extend from this base class.
  5. */
  6. class Controller extends CController
  7. {
  8. /**
  9. * @var string the default layout for the controller view. Defaults to '//layouts/column1',
  10. * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
  11. */
  12. public $layout='//layouts/column1';
  13. public array $authIds = [];
  14. public array $companyIds = [];
  15. public array $schoolIds = [];
  16. public int $authType = AUTH_TYPE_COMPANY_SCHOOL;
  17. private int $_userId = 0;
  18. /**
  19. * 检查请求方是否合法
  20. * @return void
  21. * @throws CHttpException
  22. */
  23. public function checkRequest(): void
  24. {
  25. if (LWM_ENV == 'dev') {
  26. header("Access-Control-Allow-Origin: *");
  27. } else {
  28. if (!str_contains(Yii::app()->request->hostInfo, Yii::app()->params['url'])) {
  29. throw new CHttpException(403, '非法访问');
  30. }
  31. header("Access-Control-Allow-Origin:" . Yii::app()->request->hostInfo);
  32. }
  33. header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
  34. header("Access-Control-Allow-Headers: Content-Type, Authorization, Cookie");
  35. if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  36. exit(0); // 预检请求直接返回
  37. }
  38. }
  39. public function checkSign()
  40. {
  41. if (!\Yii::app()->request->isPostRequest || !empty($_FILES)) {
  42. return true;
  43. }
  44. if (!isset($_POST['sign'])) {
  45. return false;
  46. }
  47. if (!isset($_POST['timestamp']) || $_POST['timestamp'] < time() - 10) {
  48. return false;
  49. }
  50. $postSign = $_POST['sign'];
  51. unset($_POST['sign']); // 签名不计算sign
  52. $stringArray = []; // 对参与签名的参数进行排序
  53. foreach ($_POST as $k => $v) {
  54. if (is_array($v)) {
  55. $v = implode(',', $v);
  56. }
  57. $stringArray[] = $k . '=' . trim($v);
  58. }
  59. sort($stringArray, SORT_STRING);
  60. $query = implode('&', $stringArray) . 'qwer';
  61. $query = str_replace(["\r", "\n"], '', $query);
  62. $sign = strtoupper(hash('sha256', $query));
  63. if ($sign != $postSign) {
  64. Logger::errorMult('签名错误', $query, $sign);
  65. return false;
  66. }
  67. return true;
  68. }
  69. /**
  70. * 限制操作频率
  71. * @param $second
  72. * @return void|null
  73. * @throws RedisException
  74. */
  75. public function dobuleCheck($second = 3)
  76. {
  77. $key = 'dobule_' . $this->_userId;
  78. if (!RedisInstance::getInstance()->setNx($key, 1, $second)) {
  79. return Helper::error('操作过于频繁');
  80. }
  81. }
  82. /**
  83. * @throws CHttpException
  84. */
  85. public function beforeAction($action): bool
  86. {
  87. $this->checkRequest();
  88. $token = $_SERVER['HTTP_AUTHORIZATION']?? '';
  89. $data = RedisInstance::getInstance()->get('user_token:'.$token);
  90. $this->_userId = $data['id']?? 0;
  91. Yii::app()->language = 'zh_cn';
  92. $controller = Yii::app()->controller->id;
  93. $action = $this->getAction()->getId();
  94. $path = strtolower($controller . '/'. $action);
  95. if( !in_array($controller, ['site'])
  96. &&!in_array($path, LewaimaiAdminPingtaiAuth::$noLoginRouters)
  97. && !$this->_userId
  98. ){
  99. Helper::error('请先登入', 401);
  100. }
  101. if (!$this->checkSign()) {
  102. Helper::error('签名错误', 402);
  103. }
  104. // 获取权限相关数据
  105. $this->_formatAuth();
  106. if (!LewaimaiAdminPingtaiAuth::adminAuth($controller, $action)
  107. && ($this->_userId && $this->_userId != 1)
  108. ) {
  109. Helper::error('您没有相应的权限');
  110. }
  111. return true;
  112. }
  113. /**
  114. * 整理权限数据
  115. * @return void
  116. * @throws CException
  117. * @throws CHttpException
  118. * @throws RedisException
  119. */
  120. private function _formatAuth(): void
  121. {
  122. $key = 'user_auth_' . $this->_userId;
  123. $data = RedisInstance::getInstance()->get($key);
  124. if (!$data) {
  125. $user = DB::getInfoWithCriteria('useradmin', DbCriteria::simpleCompare(['u.id' => $this->_userId])
  126. ->setAlias('u')
  127. ->setSelect('company_ids, school_ids, date_auth_type, auth_ids,cities')
  128. ->setJoin('left join wx_role r ON r.id = u.role_id'));
  129. if (!$user) {
  130. throw new CHttpException(401, '用户不存在');
  131. }
  132. $this->authIds = $user['auth_ids'] ? explode(',', $user['auth_ids']) : [];
  133. $this->authType = $user['date_auth_type'];
  134. if ($this->authType == AUTH_TYPE_COMPANY_SCHOOL) {
  135. $this->companyIds = $user['company_ids'] ? explode(',', $user['company_ids']) : [];
  136. $this->schoolIds = $user['school_ids'] ? explode(',', $user['school_ids']) : [];
  137. } elseif ($this->authType == AUTH_TYPE_CITY) {
  138. $cities = array_filter(explode(',', $user['cities']));
  139. if ($cities) {
  140. $this->companyIds = Helper::arrayColumn(DB::getListWithCriteria('company', DbCriteria::simpleCompare(['is_del' => 0, 'city' => $cities])->setSelect('id')), 'id') ?: [-9999];
  141. $this->schoolIds = Helper::arrayColumn(DB::getListWithCriteria('school', DbCriteria::simpleCompare(['is_del' => 0, 'city' => $cities])->setSelect('id')), 'id') ?: [-9999];
  142. } else {
  143. $this->companyIds = [-9999];
  144. $this->schoolIds = [-9999];
  145. }
  146. } else {
  147. $this->companyIds = [-1];
  148. $this->schoolIds = [-1];
  149. }
  150. $json = json_encode([
  151. 'authIds' => $this->authIds,
  152. 'companyIds' => $this->companyIds,
  153. 'schoolIds' => $this->schoolIds,
  154. 'authType' => $this->authType,
  155. ]);
  156. RedisInstance::getInstance()->set($key, $json, 86400);
  157. } else {
  158. $data = json_decode($data, true);
  159. $this->authIds = $data['authIds'];
  160. $this->companyIds = $data['companyIds'];
  161. $this->schoolIds = $data['schoolIds'];
  162. $this->authType = $data['authType']?? AUTH_TYPE_COMPANY_SCHOOL;
  163. }
  164. LewaimaiAdminPingtaiAuth::$authIds = $this->authIds;
  165. }
  166. public function clearAuth($id = 0)
  167. {
  168. $id = $id ? : $this->_userId;
  169. RedisInstance::getInstance()->delete('user_auth_' . $id);
  170. }
  171. public function clearAuthByCity(string $city): void
  172. {
  173. // 清除缓存
  174. $cri = DbCriteria::simpleCompare(['status' => 1])
  175. ->setSelect('id')
  176. ->addCondition("find_in_set('{$city}', cities)");
  177. $users = DB::getListWithCriteria('useradmin', $cri)?:[];
  178. Logger::errorMult('auth_change', $users);
  179. foreach ($users['records'] as $user) {
  180. $this->clearAuth($user['id']);
  181. }
  182. }
  183. public function getUserId()
  184. {
  185. return $this->_userId;
  186. }
  187. public function getSchoolFilter($filed = 'school_id'):?array
  188. {
  189. if ($this->_userId == 1 || in_array(-1, $this->companyIds)) {
  190. return null;
  191. }
  192. return $this->schoolIds;
  193. }
  194. public function checkSchoolId(int $id):bool
  195. {
  196. if ($this->_userId == 1 || in_array(-1, $this->schoolIds)) {
  197. return true;
  198. }
  199. return in_array($id, $this->schoolIds);
  200. }
  201. public function getCompanyFilter():?array
  202. {
  203. if ($this->_userId == 1 || in_array(-1, $this->companyIds)) {
  204. return null;
  205. }
  206. return $this->companyIds;
  207. }
  208. public function checkCompanyId(int $id):bool
  209. {
  210. if ($this->_userId == 1 || in_array(-1, $this->companyIds)) {
  211. return true;
  212. }
  213. return in_array($id, $this->companyIds);
  214. }
  215. }