LoginServices.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\services\store;
  13. use app\Request;
  14. use app\services\BaseServices;
  15. use app\dao\store\SystemStoreStaffDao;
  16. use app\services\system\SystemMenusServices;
  17. use app\services\system\SystemRoleServices;
  18. use crmeb\exceptions\AdminException;
  19. use crmeb\exceptions\AuthException;
  20. use crmeb\services\CacheService;
  21. use crmeb\utils\ApiErrorCode;
  22. use crmeb\utils\JwtAuth;
  23. use Firebase\JWT\ExpiredException;
  24. use think\exception\ValidateException;
  25. use think\facade\Cache;
  26. /**
  27. *
  28. * Class LoginServices
  29. * @package app\services\user
  30. * @mixin SystemStoreStaffDao
  31. */
  32. class LoginServices extends BaseServices
  33. {
  34. /**
  35. * 当前门店权限缓存前缀
  36. */
  37. const STORE_RULES_LEVEL = 'store_rules_level_';
  38. /**
  39. * LoginServices constructor.
  40. * @param SystemStoreStaffDao $dao
  41. */
  42. public function __construct(SystemStoreStaffDao $dao)
  43. {
  44. $this->dao = $dao;
  45. }
  46. /**
  47. * 获取登陆前的login等信息
  48. * @return array
  49. */
  50. public function getLoginInfo()
  51. {
  52. return [
  53. 'slide' => sys_data('admin_login_slide') ?? [],
  54. 'logo_square' => sys_config('site_logo_square'),//透明
  55. 'logo_rectangle' => sys_config('site_logo'),//方形
  56. 'login_logo' => sys_config('start_login_logo'),//登陆
  57. 'site_name' => sys_config('site_name'),
  58. 'site_url' => sys_config('site_url'),
  59. 'upload_file_size_max' => config('upload.filesize'),//文件上传大小kb
  60. ];
  61. }
  62. /**
  63. * 门店登录
  64. * @param $account
  65. * @param $password
  66. * @param $type
  67. * @param $id
  68. * @return array
  69. * @throws \think\db\exception\DataNotFoundException
  70. * @throws \think\db\exception\DbException
  71. * @throws \think\db\exception\ModelNotFoundException
  72. */
  73. public function login($account, $password, $type, $id = 0)
  74. {
  75. $where = ['account|phone' => $account, 'is_del' => 0];
  76. if ($id) {//后台快速登录 验证门店ID
  77. $where['store_id'] = $id;
  78. }
  79. $storeStaffInfo = $this->dao->getOne($where);
  80. $key = 'store_login_captcha_' . $account;
  81. if (!$storeStaffInfo) {
  82. Cache::inc($key);
  83. throw new AdminException('账号不存在!');
  84. }
  85. if ($password) {//平台还可以登录
  86. if (!$storeStaffInfo->status) {
  87. Cache::inc($key);
  88. throw new AdminException('您已被禁止登录!');
  89. }
  90. if (!password_verify($password, $storeStaffInfo->pwd)) {
  91. Cache::inc($key);
  92. throw new AdminException('账号或密码错误,请重新输入');
  93. }
  94. }
  95. $storeStaffInfo->last_time = time();
  96. $storeStaffInfo->last_ip = app('request')->ip();
  97. $storeStaffInfo->login_count++;
  98. $storeStaffInfo->save();
  99. $tokenInfo = $this->createToken($storeStaffInfo->id, $type, $storeStaffInfo->pwd);
  100. /** @var SystemMenusServices $services */
  101. $services = app()->make(SystemMenusServices::class);
  102. [$menus, $uniqueAuth] = $services->getMenusList($storeStaffInfo->roles, (int)$storeStaffInfo['level'], 2);
  103. /** @var SystemStoreServices $storeServices */
  104. $storeServices = app()->make(SystemStoreServices::class);
  105. $store = $storeServices->get((int)$storeStaffInfo['store_id'], ['id', 'image']);
  106. return [
  107. 'token' => $tokenInfo['token'],
  108. 'expires_time' => $tokenInfo['params']['exp'],
  109. 'menus' => $menus,
  110. 'unique_auth' => $uniqueAuth,
  111. 'user_info' => [
  112. 'id' => $storeStaffInfo->getData('id'),
  113. 'account' => $storeStaffInfo->getData('account'),
  114. 'avatar' => $storeStaffInfo->getData('avatar'),
  115. ],
  116. 'logo' => $store && isset($store['image']) && $store['image'] ? $store['image'] : sys_config('site_logo'),
  117. 'logo_square' => $store && isset($store['image']) && $store['image'] ? $store['image'] : sys_config('site_logo_square'),
  118. 'version' => get_crmeb_version(),
  119. 'newOrderAudioLink' => get_file_link(sys_config('new_order_audio_link', '')),
  120. 'prefix' => config('admin.store_prefix')
  121. ];
  122. }
  123. /**
  124. * 重置密码
  125. * @param $account
  126. * @param $password
  127. */
  128. public function reset($account, $password)
  129. {
  130. $user = $this->dao->getOne(['account|phone' => $account]);
  131. if (!$user) {
  132. throw new ValidateException('用户不存在');
  133. }
  134. if (!$this->dao->update($user['uid'], ['pwd' => md5((string)$password)], 'uid')) {
  135. throw new ValidateException('修改密码失败');
  136. }
  137. return true;
  138. }
  139. /**
  140. * 获取Admin授权信息
  141. * @param string $token
  142. * @return array
  143. * @throws \Psr\SimpleCache\InvalidArgumentException
  144. */
  145. public function parseToken(string $token): array
  146. {
  147. /** @var CacheService $cacheService */
  148. $cacheService = app()->make(CacheService::class);
  149. if (!$token || $token === 'undefined') {
  150. throw new AuthException(ApiErrorCode::ERR_LOGIN);
  151. }
  152. //检测token是否过期
  153. $md5Token = md5($token);
  154. if (!$cacheService->hasToken($md5Token) || !($cacheToken = $cacheService->getTokenBucket($md5Token))) {
  155. throw new AuthException(ApiErrorCode::ERR_LOGIN);
  156. }
  157. //是否超出有效次数
  158. if (isset($cacheToken['invalidNum']) && $cacheToken['invalidNum'] >= 3) {
  159. if (!request()->isCli()) {
  160. $cacheService->clearToken($md5Token);
  161. }
  162. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  163. }
  164. /** @var JwtAuth $jwtAuth */
  165. $jwtAuth = app()->make(JwtAuth::class);
  166. //设置解析token
  167. [$id, $type, $auth] = $jwtAuth->parseToken($token);
  168. //验证token
  169. try {
  170. $jwtAuth->verifyToken();
  171. $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
  172. } catch (ExpiredException $e) {
  173. $cacheToken['invalidNum'] = isset($cacheToken['invalidNum']) ? $cacheToken['invalidNum']++ : 1;
  174. $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
  175. } catch (\Throwable $e) {
  176. if (!request()->isCli()) {
  177. $cacheService->clearToken($md5Token);
  178. }
  179. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  180. }
  181. //获取管理员信息
  182. $storeStaffInfo = $this->dao->get($id);
  183. if (!$storeStaffInfo || !$storeStaffInfo->id || $storeStaffInfo->is_del) {
  184. if (!request()->isCli()) {
  185. $cacheService->clearToken($md5Token);
  186. }
  187. throw new AuthException(ApiErrorCode::ERR_LOGIN_STATUS);
  188. }
  189. if ($auth !== md5($storeStaffInfo->pwd)) {
  190. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  191. }
  192. $storeStaffInfo->type = $type;
  193. return $storeStaffInfo->hidden(['pwd', 'is_del', 'status'])->toArray();
  194. }
  195. /**
  196. * 后台验证权限
  197. * @param Request $request
  198. */
  199. public function verifiAuth(Request $request)
  200. {
  201. $rule = str_replace('storeapi/', '', trim(strtolower($request->rule()->getRule())));
  202. if (in_array($rule, ['store/logout', 'menuslist'])) {
  203. return true;
  204. }
  205. $method = trim(strtolower($request->method()));
  206. /** @var SystemRoleServices $roleServices */
  207. $roleServices = app()->make(SystemRoleServices::class);
  208. $auth = $roleServices->getAllRoles(2, 2, self::STORE_RULES_LEVEL);
  209. //验证访问接口是否存在
  210. if ($auth && !in_array($method . '@@' . $rule, array_map(function ($item) {
  211. return trim(strtolower($item['methods'])). '@@'. trim(strtolower(str_replace(' ', '', $item['api_url'])));
  212. }, $auth))) {
  213. return true;
  214. }
  215. $auth = $roleServices->getRolesByAuth($request->storeStaffInfo()['roles'], 2, 2, self::STORE_RULES_LEVEL);
  216. //验证访问接口是否有权限
  217. if ($auth && empty(array_filter($auth, function ($item) use ($rule, $method) {
  218. if (trim(strtolower($item['api_url'])) === $rule && $method === trim(strtolower($item['methods'])))
  219. return true;
  220. }))) {
  221. throw new AuthException(ApiErrorCode::ERR_AUTH);
  222. }
  223. }
  224. }