LoginServices.php 9.2 KB

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