UserAuth.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: leo
  5. * Date: 2018/2/28
  6. * Time: 上午10:31
  7. */
  8. namespace backendApi\modules\v1\components;
  9. use backendApi\modules\v1\models\Admin;
  10. use backendApi\modules\v1\models\AdminRole;
  11. use backendApi\modules\v1\models\AdminToken;
  12. use common\components\Request;
  13. use common\helpers\Cache;
  14. use common\helpers\Date;
  15. use common\helpers\Form;
  16. use common\helpers\Log;
  17. use common\helpers\Tool;
  18. use common\models\UserInfo;
  19. use common\models\UserToken;
  20. use Yii;
  21. use yii\db\ActiveRecordInterface;
  22. use yii\helpers\Json;
  23. use yii\web\HttpException;
  24. use yii\web\IdentityInterface;
  25. use yii\web\User;
  26. class UserAuth extends User
  27. {
  28. private $_userId = null;
  29. private $_apiIdentity = null;
  30. private $_token = null;
  31. private $_userInfo = null;
  32. private $_device = null;
  33. private $_deviceInfo = null;
  34. /**
  35. * 初始化设备信息
  36. * @throws \yii\base\InvalidConfigException
  37. */
  38. public function init()
  39. {
  40. parent::init();
  41. $this->_device = Yii::$app->request->getDevice();
  42. $this->_deviceInfo = Yii::$app->request->getDeviceInfo();
  43. }
  44. /**
  45. * 首次以用户名和密码的方式登录
  46. * @param IdentityInterface $identity
  47. * @return bool
  48. * @throws HttpException
  49. */
  50. public function loginWithUAndP(IdentityInterface $identity){
  51. if ($this->beforeLogin($identity, false, 0)) {
  52. $id = $identity->getId();
  53. $ip = Yii::$app->getRequest()->getUserIP();
  54. $this->_userId = $identity['ID'];
  55. $this->_apiIdentity = $identity;
  56. $this->_userInfo = [
  57. 'id' => $identity['ID'],
  58. 'adminName' => $identity['ADMIN_NAME'],
  59. 'roleId' => $identity['ROLE_ID'],
  60. 'accessTokenUpdatedAt' => Date::nowTime(),
  61. 'ip' => $ip,
  62. ];
  63. Admin::updateAll(['LAST_LOGIN_IP' => $ip, 'LAST_LOGIN_AT' => Date::nowTime()], 'ID=:ID', [':ID'=>$identity['ID']]);
  64. $userToken = AdminToken::findOne(['ADMIN_ID' => $identity['ID']]);
  65. if(!$userToken){
  66. $userToken = new AdminToken();
  67. $userToken->ADMIN_ID = $identity['ID'];
  68. $userToken->CREATED_AT = Date::nowTime();
  69. $userToken->save();
  70. }
  71. $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'access');
  72. $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'refresh');
  73. $this->afterLogin($identity, false, 0);
  74. }
  75. return !$this->getIsGuest();
  76. }
  77. public function afterLogin($identity, $cookieBased, $duration)
  78. {
  79. parent::afterLogin($identity, $cookieBased, $duration);
  80. // 记录管理员登录日志
  81. // Log::adminLogin();
  82. }
  83. /**
  84. * 已AccessToken方式登录(即平时直接访问)
  85. * @param string $token
  86. * @param null $type
  87. * @return null|IdentityInterface
  88. */
  89. public function loginByAccessToken($token, $type = null)
  90. {
  91. /* @var $class IdentityInterface */
  92. $class = $this->identityClass;
  93. $userId = $this->_userId = $class::findIdentityByAccessToken($token, $type);
  94. if($userId){
  95. $this->_userInfo = [
  96. 'id' => $userId,
  97. 'adminName' => Yii::$app->tokenRedis->hget($token, 'ADMIN_NAME'),
  98. 'roleId' => Yii::$app->tokenRedis->hget($token, 'ROLE_ID'),
  99. 'accessTokenUpdatedAt' => Yii::$app->tokenRedis->hget($token, 'TOKEN_UPDATED_AT'),
  100. 'ip' => Yii::$app->getRequest()->getUserIP(),
  101. ];
  102. return $userId;
  103. } else {
  104. return null;
  105. }
  106. }
  107. /**
  108. * 用refreshToken生成新的accessToken和refreshToken
  109. * @param $refreshToken
  110. * @return bool
  111. * @throws HttpException
  112. */
  113. public function refreshToken($refreshToken){
  114. if(!$refreshToken){
  115. return false;
  116. }
  117. $userId = Yii::$app->tokenRedis->hget($refreshToken, 'ID');
  118. if(!$userId){
  119. return false;
  120. }
  121. $userToken = AdminToken::findOne(['ADMIN_ID' => $userId]);
  122. $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'access', $userId);
  123. $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'refresh', $userId);
  124. return true;
  125. }
  126. /**
  127. * 用refreshToken生成新的accessToken
  128. * @param $refreshToken
  129. * @return bool
  130. * @throws HttpException
  131. */
  132. public function refreshAccessToken($refreshToken){
  133. if(!$refreshToken){
  134. return false;
  135. }
  136. $userId = Yii::$app->tokenRedis->hget($refreshToken, 'ID');
  137. if(!$userId){
  138. return false;
  139. }
  140. $userToken = AdminToken::findOne(['ADMIN_ID' => $userId]);
  141. return $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'access', $userId);
  142. }
  143. /**
  144. * 用refreshToken生成新的refreshToken
  145. * @param $refreshToken
  146. * @return bool
  147. * @throws HttpException
  148. */
  149. public function refreshRefreshToken($refreshToken){
  150. if(!$refreshToken){
  151. return false;
  152. }
  153. $userId = Yii::$app->tokenRedis->hget($refreshToken, 'ID');
  154. if(!$userId){
  155. return false;
  156. }
  157. $userToken = AdminToken::findOne(['ADMIN_ID' => $userId]);
  158. return $this->updateToken($userToken, $appType = $this->_device, $typeToken = 'refresh', $userId);
  159. }
  160. /**
  161. * 更新token 的具体方法
  162. * @param ActiveRecordInterface $userTokenModel
  163. * @param string $appType (pc|app)
  164. * @param string $typeToken
  165. * @param $userId
  166. * @return bool
  167. * @throws HttpException
  168. */
  169. public function updateToken(ActiveRecordInterface $userTokenModel, $appType = Request::DEVICE_PC, $typeToken = 'access', $userId = 0){
  170. $tokenField = strtoupper($appType.'_'.$typeToken.'_TOKEN');
  171. $updateField = '';
  172. $expiresIn = 0;
  173. if($appType === Request::DEVICE_PC){
  174. if($typeToken === 'access'){
  175. $updateField = 'PAT_UPDATED_AT';
  176. $expiresIn = Yii::$app->params['backAccessTokenExpiresIn'];
  177. } elseif ($typeToken === 'refresh'){
  178. $updateField = 'PRT_UPDATED_AT';
  179. $expiresIn = Yii::$app->params['backRefreshTokenExpiresIn'];
  180. } else {
  181. throw new HttpException(500, 'token字段错误', 500);
  182. }
  183. } elseif ($appType === Request::DEVICE_APP){
  184. if($typeToken === 'access'){
  185. $updateField = 'AAT_UPDATED_AT';
  186. $expiresIn = Yii::$app->params['backAccessTokenExpiresIn'];
  187. } elseif ($typeToken === 'refresh'){
  188. $updateField = 'ART_UPDATED_AT';
  189. $expiresIn = Yii::$app->params['backRefreshTokenExpiresIn'];
  190. } else {
  191. throw new HttpException(500, 'token字段错误', 500);
  192. }
  193. }
  194. // 老token
  195. $oldToken = $userTokenModel->$tokenField;
  196. // 生成 access_token
  197. /* @var $identityClass IdentityInterface */
  198. $identityClass = $this->identityClass;
  199. $generateTokenMethodName = 'generate'.ucfirst($typeToken).'Token';
  200. //$token = $identityClass::generateAccessToken();
  201. $token = call_user_func([$identityClass, $generateTokenMethodName], $appType);
  202. $userTokenModel->$tokenField = $token;
  203. $userTokenModel->$updateField = Date::nowTime();
  204. if(!$userTokenModel->save()){
  205. throw new HttpException(500, 'token更新失败', 500);
  206. }
  207. // 查找TOKEN中是否有同一用户产生的垃圾token,有的话就清除
  208. Yii::$app->tokenRedis->del($oldToken);
  209. $identity = $this->_apiIdentity;
  210. if(!$this->_apiIdentity){
  211. if(!$userId){
  212. throw new HttpException(500, 'userId不能为空', 500);
  213. }
  214. $identity = $identityClass::findIdentity($userId);
  215. }
  216. // 把 accessToken 当做key存入redis中内容为会员的ID和用户名
  217. Yii::$app->tokenRedis->hset($token, 'ID', $identity['ID']);
  218. Yii::$app->tokenRedis->hset($token, 'ADMIN_NAME', $identity['ADMIN_NAME']);
  219. Yii::$app->tokenRedis->hset($token, 'ROLE_ID', $identity['ROLE_ID']);
  220. Yii::$app->tokenRedis->hset($token, 'TOKEN_UPDATED_AT', $userTokenModel->$updateField);
  221. Yii::$app->tokenRedis->expire($token, $expiresIn);
  222. $this->_token = array_merge($this->_token ? $this->_token : [], [
  223. $typeToken.'Token' => $token,
  224. $typeToken.'TokenExpiresIn' => $expiresIn,
  225. $typeToken.'TokenUpdateAt' => $userTokenModel->$updateField,
  226. ]);
  227. return true;
  228. }
  229. /**
  230. * 获取管理员ID
  231. * @return int|null|string
  232. */
  233. public function getId()
  234. {
  235. return $this->_userId;
  236. }
  237. /**
  238. * 获取token
  239. * @return null
  240. */
  241. public function getToken(){
  242. return $this->_token;
  243. }
  244. /**
  245. * 获取管理员信息
  246. * @return null
  247. */
  248. public function getUserInfo(){
  249. return $this->_userInfo;
  250. }
  251. /**
  252. * 获取身份信息
  253. * @param bool $autoRenew
  254. * @return null|IdentityInterface
  255. */
  256. public function getIdentity($autoRenew = true)
  257. {
  258. if($this->_apiIdentity){
  259. return $this->_apiIdentity;
  260. } else {
  261. if($this->_userId){
  262. /* @var $class IdentityInterface */
  263. $class = $this->identityClass;
  264. return $class::findOne(['ID' => $this->_userId]);
  265. } else {
  266. return null;
  267. }
  268. }
  269. }
  270. /**
  271. * 获取管理员权限
  272. * @return mixed
  273. */
  274. public function getAdminPermission(){
  275. $userInfo = $this->_userInfo;
  276. $adminRoles = Cache::getAdminRole();
  277. //$role = AdminRole::findOne(['ID'=>$userInfo['roleId']]);
  278. return $adminRoles[$userInfo['roleId']]['PERMISSION'];
  279. }
  280. /**
  281. * 校验管理员权限
  282. * @param $controller
  283. * @param string $action
  284. * @return bool
  285. */
  286. public function validateAdminAction($controller, $action = ''){
  287. // 查看控制器是否在白名单中,如果在白名单中则直接返回true
  288. $noCheckActions = Yii::$app->params['noCheckPermissionActions'];
  289. if(in_array($controller.'/'.$action, $noCheckActions)){
  290. return true;
  291. }
  292. $userInfo = $this->_userInfo;
  293. if($userInfo && isset($userInfo) && $userInfo['roleId'] === Yii::$app->params['superAdminRoleId']){
  294. return true;
  295. }
  296. // 获取管理员权限
  297. $permission = $this->getAdminPermission();
  298. if(!$permission){
  299. return false;
  300. }
  301. if($controller && $action){
  302. if(in_array($controller.'/'.$action, $permission)){
  303. return true;
  304. }
  305. }
  306. // elseif ($controller){
  307. // $pattern = '/'.$controller.'\//';
  308. // foreach($permission as $value){
  309. // if(preg_match($pattern, $value)){
  310. // return true;
  311. // }
  312. // }
  313. // }
  314. return false;
  315. }
  316. /**
  317. * 查看是否有该控制器的权限
  318. * @param $controller
  319. * @return bool
  320. */
  321. public function validateAdminController($controller){
  322. $userInfo = $this->_userInfo;
  323. if($userInfo && isset($userInfo) && $userInfo['roleId'] === Yii::$app->params['superAdminRoleId']){
  324. return true;
  325. }
  326. $result = false;
  327. // 查看控制器是否在白名单中,如果在白名单中则直接返回true
  328. $noCheckActions = Yii::$app->params['noCheckPermissionActions'];
  329. foreach($noCheckActions as $action){
  330. if(preg_match('/^'.$controller.'\//', $action)){
  331. $result = true;
  332. break;
  333. }
  334. }
  335. // 查看会员的权限
  336. $permissions = $this->getAdminPermission();
  337. if($permissions){
  338. foreach($permissions as $permission){
  339. if(preg_match('/^'.$controller.'\//', $permission)){
  340. $result = true;
  341. break;
  342. }
  343. }
  344. }
  345. return $result;
  346. }
  347. /**
  348. * 不需要检查管理员权限的控制器
  349. * @param $controller
  350. * @return bool
  351. */
  352. public function noCheckAdminController($controller){
  353. $userInfo = $this->_userInfo;
  354. if($userInfo && isset($userInfo) && $userInfo['roleId'] === Yii::$app->params['superAdminRoleId']){
  355. return false;
  356. }
  357. $result = false;
  358. // 查看控制器是否在白名单中,如果在白名单中则直接返回true
  359. $noCheckActions = Yii::$app->params['noCheckPermissionActions'];
  360. foreach($noCheckActions as $action){
  361. if(preg_match('/^'.$controller.'\//', $action)){
  362. $result = true;
  363. break;
  364. }
  365. }
  366. // 查看会员的权限
  367. $permissions = $this->getAdminPermission();
  368. if($permissions){
  369. foreach($permissions as $permission){
  370. if(preg_match('/^'.$controller.'\//', $permission)){
  371. $result = false;
  372. break;
  373. }
  374. }
  375. }
  376. return $result;
  377. }
  378. }