LoginServices.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 (!password_verify($password, $supplierInfo->pwd)) {
  89. Cache::inc($key);
  90. throw new AdminException('账号或密码错误,请重新输入');
  91. }
  92. }
  93. $supplierInfo->last_time = time();
  94. $supplierInfo->last_ip = app('request')->ip();
  95. $supplierInfo->login_count++;
  96. $supplierInfo->save();
  97. $tokenInfo = $this->createToken($supplierInfo['id'], $type, $supplierInfo->pwd);
  98. /** @var SystemMenusServices $services */
  99. $services = app()->make(SystemMenusServices::class);
  100. [$menus, $uniqueAuth] = $services->getMenusList($supplierInfo->roles, 0, 4);
  101. return [
  102. 'token' => $tokenInfo['token'],
  103. 'expires_time' => $tokenInfo['params']['exp'],
  104. 'menus' => $menus,
  105. 'unique_auth' => $uniqueAuth,
  106. 'user_info' => [
  107. 'id' => $supplierInfo->getData('id'),
  108. 'account' => $supplierInfo->getData('account'),
  109. 'avatar' => $supplierInfo->getData('head_pic'),
  110. ],
  111. 'logo' => sys_config('site_logo'),
  112. 'logo_square' => sys_config('site_logo_square'),
  113. 'version' => get_crmeb_version(),
  114. 'newOrderAudioLink' => get_file_link(sys_config('new_order_audio_link', '')),
  115. 'prefix' => config('admin.supplier_prefix')
  116. ];
  117. }
  118. /**
  119. * 重置密码
  120. * @param $account
  121. * @param $password
  122. */
  123. public function reset($account, $password)
  124. {
  125. $user = $this->dao->getOne(['account|phone' => $account]);
  126. if (!$user) {
  127. throw new ValidateException('用户不存在');
  128. }
  129. if (!$this->dao->update($user['id'], ['pwd' => md5((string)$password)])) {
  130. throw new ValidateException('修改密码失败');
  131. }
  132. return true;
  133. }
  134. /**
  135. * 获取Admin授权信息
  136. * @param string $token
  137. * @return array
  138. * @throws \Psr\SimpleCache\InvalidArgumentException
  139. */
  140. public function parseToken(string $token): array
  141. {
  142. /** @var CacheService $cacheService */
  143. $cacheService = app()->make(CacheService::class);
  144. if (!$token || $token === 'undefined') {
  145. throw new AuthException(ApiErrorCode::ERR_LOGIN);
  146. }
  147. //检测token是否过期
  148. $md5Token = md5($token);
  149. if (!$cacheService->hasToken($md5Token) || !($cacheToken = $cacheService->getTokenBucket($md5Token))) {
  150. throw new AuthException(ApiErrorCode::ERR_LOGIN);
  151. }
  152. //是否超出有效次数
  153. if (isset($cacheToken['invalidNum']) && $cacheToken['invalidNum'] >= 3) {
  154. if (!request()->isCli()) {
  155. $cacheService->clearToken($md5Token);
  156. }
  157. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  158. }
  159. /** @var JwtAuth $jwtAuth */
  160. $jwtAuth = app()->make(JwtAuth::class);
  161. //设置解析token
  162. [$id, $type, $auth] = $jwtAuth->parseToken($token);
  163. //验证token
  164. try {
  165. $jwtAuth->verifyToken();
  166. $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
  167. } catch (ExpiredException $e) {
  168. $cacheToken['invalidNum'] = isset($cacheToken['invalidNum']) ? $cacheToken['invalidNum']++ : 1;
  169. $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
  170. } catch (\Throwable $e) {
  171. if (!request()->isCli()) {
  172. $cacheService->clearToken($md5Token);
  173. }
  174. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  175. }
  176. //获取管理员信息
  177. $adminInfo = $this->adminDao->getOne(['id' => $id, 'is_del' => 0, 'status' => 1]);
  178. if(!$adminInfo){
  179. throw new AuthException(ApiErrorCode::ERR_ADMINID_VOID);
  180. }
  181. if ($auth !== md5($adminInfo->pwd)) {
  182. throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
  183. }
  184. $supplierInfo = $this->dao->getOne(['id' =>(int)$adminInfo->relation_id, 'is_del' => 0], '*', ['admin']);
  185. if (!$supplierInfo || !$supplierInfo->account || $supplierInfo->admin_is_del) {
  186. if (!request()->isCli()) {
  187. $cacheService->clearToken($md5Token);
  188. }
  189. throw new AuthException(ApiErrorCode::ERR_LOGIN_STATUS);
  190. }
  191. $supplierInfo->type = $type;
  192. return $supplierInfo->hidden(['pwd', 'is_del', 'status'])->toArray();
  193. }
  194. /**
  195. * 后台验证权限
  196. * @param Request $request
  197. */
  198. public function verifiAuth(Request $request)
  199. {
  200. // TODO: 供应商不做验证
  201. return true;
  202. $rule = str_replace('supplierapi/', '', trim(strtolower($request->rule()->getRule())));
  203. if (in_array($rule, ['supplier/logout', 'menuslist'])) {
  204. return true;
  205. }
  206. $method = trim(strtolower($request->method()));
  207. /** @var SystemRoleServices $roleServices */
  208. $roleServices = app()->make(SystemRoleServices::class);
  209. $auth = $roleServices->getAllRoles(2, 4, self::SUPPLIER_RULES_LEVEL);
  210. //验证访问接口是否存在
  211. if ($auth && !in_array($method . '@@' . $rule, array_map(function ($item) {
  212. return trim(strtolower($item['methods'])). '@@'. trim(strtolower(str_replace(' ', '', $item['api_url'])));
  213. }, $auth))) {
  214. return true;
  215. }
  216. $auth = $roleServices->getRolesByAuth($request->supplierInfo()['roles'], 2, 4, self::SUPPLIER_RULES_LEVEL);
  217. //验证访问接口是否有权限
  218. if ($auth && empty(array_filter($auth, function ($item) use ($rule, $method) {
  219. if (trim(strtolower($item['api_url'])) === $rule && $method === trim(strtolower($item['methods'])))
  220. return true;
  221. }))) {
  222. throw new AuthException(ApiErrorCode::ERR_AUTH);
  223. }
  224. }
  225. }