Auth.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\controller\api;
  12. use app\common\repositories\store\order\StoreGroupOrderRepository;
  13. use app\common\repositories\store\order\StoreOrderRepository;
  14. use app\common\repositories\store\order\StoreRefundOrderRepository;
  15. use app\common\repositories\system\notice\SystemNoticeConfigRepository;
  16. use app\common\repositories\user\UserOrderRepository;
  17. use app\common\repositories\user\UserRechargeRepository;
  18. use app\common\repositories\user\UserRepository;
  19. use app\common\repositories\user\UserSignRepository;
  20. use app\common\repositories\wechat\RoutineQrcodeRepository;
  21. use app\common\repositories\wechat\WechatUserRepository;
  22. use app\validate\api\ChangePasswordValidate;
  23. use app\validate\api\UserAuthValidate;
  24. use crmeb\basic\BaseController;
  25. use crmeb\services\MiniProgramService;
  26. use crmeb\services\SmsService;
  27. use crmeb\services\WechatService;
  28. use crmeb\services\WechatTemplateMessageService;
  29. use Exception;
  30. use Firebase\JWT\JWT;
  31. use Gregwar\Captcha\CaptchaBuilder;
  32. use Gregwar\Captcha\PhraseBuilder;
  33. use Overtrue\Socialite\AccessToken;
  34. use Symfony\Component\HttpFoundation\Request;
  35. use think\db\exception\DataNotFoundException;
  36. use think\db\exception\DbException;
  37. use think\db\exception\ModelNotFoundException;
  38. use think\exception\ValidateException;
  39. use think\facade\Cache;
  40. use think\facade\Log;
  41. use think\facade\Queue;
  42. use crmeb\jobs\SendSmsJob;
  43. /**
  44. * Class Auth
  45. * @package app\controller\api
  46. * @author xaboy
  47. * @day 2020-05-06
  48. */
  49. class Auth extends BaseController
  50. {
  51. public function test()
  52. {
  53. // $data = [
  54. // 'tempId' => '',
  55. // 'id' => '',
  56. // ];
  57. // Queue::push(SendSmsJob::class,$data);
  58. // $status = app()->make(SystemNoticeConfigRepository::class)->getNoticeStatusByConstKey($data['tempId']);
  59. // if ($status['notice_sms'] == 1) {
  60. // SmsService::sendMessage($data);
  61. // }
  62. // if ($status['notice_wechat'] == 1) {
  63. // app()->make(WechatTemplateMessageService::class)->sendTemplate($data);
  64. // }
  65. // if ($status['notice_routine'] == 1) {
  66. // app()->make(WechatTemplateMessageService::class)->subscribeSendTemplate($data);
  67. // }
  68. }
  69. /**
  70. * @param UserRepository $repository
  71. * @return mixed
  72. * @throws DbException
  73. * @author xaboy
  74. * @day 2020/6/1
  75. */
  76. public function login(UserRepository $repository)
  77. {
  78. $account = $this->request->param('account');
  79. $auth_token = $this->request->param('auth_token');
  80. if (Cache::get('api_login_freeze_' . $account))
  81. return app('json')->fail('账号或密码错误次数太多,请稍后在尝试');
  82. if (!$account)
  83. return app('json')->fail('请输入账号');
  84. $user = $repository->accountByUser($this->request->param('account'));
  85. // if($auth_token && $user){
  86. // return app('json')->fail('用户已存在');
  87. // }
  88. if (!$user) $this->loginFailure($account);
  89. if (!password_verify($pwd = (string)$this->request->param('password'), $user['pwd'])) $this->loginFailure($account);
  90. $auth = $this->parseAuthToken($auth_token);
  91. if ($auth && !$user['wechat_user_id']) {
  92. $repository->syncBaseAuth($auth, $user);
  93. }
  94. $user = $repository->mainUser($user);
  95. $pid = $this->request->param('spread', 0);
  96. $repository->bindSpread($user, intval($pid));
  97. $tokenInfo = $repository->createToken($user);
  98. $repository->loginAfter($user);
  99. return app('json')->success($repository->returnToken($user, $tokenInfo));
  100. }
  101. /**
  102. * 登录尝试次数限制
  103. * @param $account
  104. * @param int $number
  105. * @param int $n
  106. * @author Qinii
  107. * @day 7/6/21
  108. */
  109. public function loginFailure($account, $number = 5, $n = 3)
  110. {
  111. $key = 'api_login_failuree_' . $account;
  112. $numb = Cache::get($key) ?? 0;
  113. $numb++;
  114. if ($numb >= $number) {
  115. $fail_key = 'api_login_freeze_' . $account;
  116. Cache::set($fail_key, 1, 15 * 60);
  117. throw new ValidateException('账号或密码错误次数太多,请稍后在尝试');
  118. } else {
  119. Cache::set($key, $numb, 5 * 60);
  120. $msg = '账号或密码错误';
  121. $_n = $number - $numb;
  122. if ($_n <= $n) {
  123. $msg .= ',还可尝试' . $_n . '次';
  124. }
  125. throw new ValidateException($msg);
  126. }
  127. }
  128. /**
  129. * @return mixed
  130. * @author xaboy
  131. * @day 2020/6/1
  132. */
  133. public function userInfo()
  134. {
  135. $user = $this->request->userInfo()->hidden(['label_id', 'group_id', 'pwd', 'addres', 'card_id', 'last_time', 'last_ip', 'create_time', 'mark', 'status', 'spread_uid', 'spread_time', 'real_name', 'birthday', 'brokerage_price']);
  136. $user->append(['service', 'topService', 'total_collect_product', 'total_collect_store', 'total_coupon', 'total_visit_product', 'total_unread', 'total_recharge', 'lock_integral', 'total_integral', 'staffs']);
  137. $data = $user->toArray();
  138. $data['total_consume'] = $user['pay_price'];
  139. $promoter = get_extension_info($user);
  140. $promoter['isShow'] = false;
  141. if ($promoter['isPromoter']) {
  142. $promoter['isShow'] = true;
  143. } else {
  144. if (!in_array($promoter['promoter_type'],[1,2])) {
  145. $promoter['isShow'] = true;
  146. }
  147. }
  148. $data['promoter'] = $promoter;
  149. if (systemConfig('member_status'))
  150. $data['member_icon'] = $this->request->userInfo()->member->brokerage_icon ?? '';
  151. if ($data['is_svip'] == 3)
  152. $data['svip_endtime'] = date('Y-m-d H:i:s', strtotime("+100 year"));
  153. $day = date('Y-m-d', time());
  154. $key = 'sign_' . $user['uid'] . '_' . $day;
  155. $data['sign_status'] = false;
  156. if (Cache::get($key)) {
  157. $data['sign_status'] = true;
  158. } else {
  159. $nu = app()->make(UserSignRepository::class)->getSign($user->uid, $day);
  160. if ($nu) {
  161. $data['sign_status'] = true;
  162. Cache::set($key, true, new \DateTime($day . ' 23:59:59'));
  163. }
  164. }
  165. $data['staff_mer'] = $data['staffs'] ? array_column($data['staffs'], 'mer_id') : [];
  166. return app('json')->success($data);
  167. }
  168. /**
  169. * @param UserRepository $repository
  170. * @return mixed
  171. * @author xaboy
  172. * @day 2020/6/1
  173. */
  174. public function logout(UserRepository $repository)
  175. {
  176. $repository->clearToken($this->request->token());
  177. return app('json')->success('退出登录');
  178. }
  179. /**
  180. * @return mixed
  181. * @throws DataNotFoundException
  182. * @throws DbException
  183. * @throws ModelNotFoundException
  184. * @author xaboy
  185. * @day 2020-05-11
  186. */
  187. public function auth()
  188. {
  189. if (systemConfig('is_phone_login') === '1') {
  190. return app('json')->fail('请绑定手机号');
  191. }
  192. $request = $this->request;
  193. $oauth = WechatService::create()->getApplication()->oauth;
  194. $oauth->setRequest(new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent()));
  195. try {
  196. $wechatInfo = $oauth->user()->getOriginal();
  197. } catch (Exception $e) {
  198. return app('json')->fail('授权失败[001]', ['message' => $e->getMessage()]);
  199. }
  200. if (!isset($wechatInfo['nickname'])) {
  201. return app('json')->fail('授权失败[002]');
  202. }
  203. /** @var WechatUserRepository $make */
  204. $make = app()->make(WechatUserRepository::class);
  205. $user = $make->syncUser($wechatInfo['openid'], $wechatInfo);
  206. if (!$user)
  207. return app('json')->fail('授权失败[003]');
  208. /** @var UserRepository $make */
  209. $userRepository = app()->make(UserRepository::class);
  210. $user[1] = $userRepository->mainUser($user[1]);
  211. $pid = $this->request->param('spread', 0);
  212. $userRepository->bindSpread($user[1], intval($pid));
  213. $tokenInfo = $userRepository->createToken($user[1]);
  214. $userRepository->loginAfter($user[1]);
  215. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  216. }
  217. /**
  218. * @return mixed
  219. * @throws DataNotFoundException
  220. * @throws DbException
  221. * @throws ModelNotFoundException
  222. * @author xaboy
  223. * @day 2020-05-11
  224. */
  225. public function mpAuth()
  226. {
  227. list($code, $post_cache_key) = $this->request->params([
  228. 'code',
  229. 'cache_key',
  230. ], true);
  231. if (systemConfig('is_phone_login') === '1') {
  232. return app('json')->fail('请绑定手机号');
  233. }
  234. $userInfoCong = Cache::get('eb_api_code_' . $code);
  235. if (!$code && !$userInfoCong)
  236. return app('json')->fail('授权失败,参数有误');
  237. $miniProgramService = MiniProgramService::create();
  238. if ($code && !$userInfoCong) {
  239. try {
  240. $userInfoCong = $miniProgramService->getUserInfo($code);
  241. Cache::set('eb_api_code_' . $code, $userInfoCong, 86400);
  242. } catch (Exception $e) {
  243. return app('json')->fail('获取session_key失败,请检查您的配置!', ['line' => $e->getLine(), 'message' => $e->getMessage()]);
  244. }
  245. }
  246. $data = $this->request->params([
  247. ['spread_spid', 0],
  248. ['spread_code', ''],
  249. ['iv', ''],
  250. ['encryptedData', ''],
  251. ]);
  252. try {
  253. //解密获取用户信息
  254. $userInfo = $miniProgramService->encryptor($userInfoCong['session_key'], $data['iv'], $data['encryptedData']);
  255. } catch (Exception $e) {
  256. if ($e->getCode() == '-41003') return app('json')->fail('获取会话密匙失败');
  257. throw $e;
  258. }
  259. if (!$userInfo) return app('json')->fail('openid获取失败');
  260. if (!isset($userInfo['openId'])) $userInfo['openId'] = $userInfoCong['openid'] ?? '';
  261. $userInfo['unionId'] = $userInfoCong['unionid'] ?? $userInfo['unionId'] ?? '';
  262. if (!$userInfo['openId']) return app('json')->fail('openid获取失败');
  263. /** @var WechatUserRepository $make */
  264. $make = app()->make(WechatUserRepository::class);
  265. $user = $make->syncRoutineUser($userInfo['openId'], $userInfo);
  266. if (!$user)
  267. return app('json')->fail('授权失败');
  268. /** @var UserRepository $make */
  269. $userRepository = app()->make(UserRepository::class);
  270. $user[1] = $userRepository->mainUser($user[1]);
  271. $code = intval($data['spread_code']['id'] ?? $data['spread_code']);
  272. //获取是否有扫码进小程序
  273. if ($code && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($code))) {
  274. $data['spread_spid'] = $info['third_id'];
  275. }
  276. $userRepository->bindSpread($user[1], intval($data['spread_spid']));
  277. $tokenInfo = $userRepository->createToken($user[1]);
  278. $userRepository->loginAfter($user[1]);
  279. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  280. }
  281. public function getCaptcha()
  282. {
  283. $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4));
  284. $key = uniqid(microtime(true), true);
  285. Cache::set('api_captche' . $key, $codeBuilder->getPhrase(), 300);
  286. $captcha = $codeBuilder->build()->inline();
  287. return app('json')->success(compact('key', 'captcha'));
  288. }
  289. protected function checkCaptcha($uni, string $code): bool
  290. {
  291. $cacheName = 'api_captche' . $uni;
  292. if (!Cache::has($cacheName)) return false;
  293. $key = Cache::get($cacheName);
  294. $res = strtolower($key) == strtolower($code);
  295. if ($res) Cache::delete($cacheName);
  296. return $res;
  297. }
  298. public function verify(UserAuthValidate $validate)
  299. {
  300. $data = $this->request->params(['phone', ['type', 'login'], ['captchaType', 'clickWord'], ['captchaVerification', ''], 'token']);
  301. //二次验证
  302. try {
  303. aj_captcha_check_two($data['captchaType'], $data['captchaVerification']);
  304. } catch (\Throwable $e) {
  305. return app('json')->fail($e->getMessage());
  306. }
  307. $validate->sceneVerify()->check($data);
  308. $sms_limit_key = 'sms_limit_' . $data['phone'];
  309. $limit = Cache::get($sms_limit_key) ? Cache::get($sms_limit_key) : 0;
  310. $sms_limit = systemConfig('sms_limit');
  311. if ($sms_limit && $limit > $sms_limit) {
  312. return app('json')->fail('请求太频繁请稍后再试');
  313. }
  314. //if(!env('APP_DEBUG', false)){
  315. try {
  316. $sms_code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);
  317. $sms_time = systemConfig('sms_time') ? systemConfig('sms_time') : 30;
  318. SmsService::create()->send($data['phone'], 'VERIFICATION_CODE', ['code' => $sms_code, 'time' => $sms_time]);
  319. } catch (Exception $e) {
  320. return app('json')->fail($e->getMessage());
  321. }
  322. //}else{
  323. // $sms_code = 1234;
  324. // $sms_time = 5;
  325. //}
  326. $sms_key = app()->make(SmsService::class)->sendSmsKey($data['phone'], $data['type']);
  327. Cache::set($sms_key, $sms_code, $sms_time * 60);
  328. Cache::set($sms_limit_key, $limit + 1, 60);
  329. //'短信发送成功'
  330. return app('json')->success('短信发送成功');
  331. }
  332. public function smsLogin(UserAuthValidate $validate, UserRepository $repository)
  333. {
  334. $data = $this->request->params(['phone', 'sms_code', 'spread', 'auth_token', ['user_type', 'h5']]);
  335. $validate->sceneSmslogin()->check($data);
  336. $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'login');
  337. if (!$sms_code) return app('json')->fail('验证码不正确');
  338. $user = $repository->accountByUser($data['phone']);
  339. if (!$user) $user = $repository->getWhere(['phone' => $data['phone']]);
  340. $auth = $this->parseAuthToken($data['auth_token']);
  341. //有auth说明是绑定手机号
  342. if ($auth && $user && $user['wechat_user_id'] && $user['wechat_user_id'] !== $auth['id'])
  343. return app('json')->fail('该手机号已被绑定');
  344. if (!$user) $user = $repository->registr($data['phone'], null, $data['user_type']);
  345. if ($auth && !$user['wechat_user_id']) {
  346. $repository->syncBaseAuth($auth, $user);
  347. }
  348. $user = $repository->mainUser($user);
  349. $repository->bindSpread($user, intval($data['spread']));
  350. $tokenInfo = $repository->createToken($user);
  351. $repository->loginAfter($user);
  352. return app('json')->success($repository->returnToken($user, $tokenInfo));
  353. }
  354. public function changePassword(ChangePasswordValidate $validate, UserRepository $repository)
  355. {
  356. $data = $this->request->params(['phone', 'sms_code', 'pwd']);
  357. $validate->check($data);
  358. $user = $repository->accountByUser($data['phone']);
  359. if (!$user) return app('json')->fail('用户不存在');
  360. $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'change_pwd');
  361. if (!$sms_code)
  362. return app('json')->fail('验证码不正确');
  363. $user->pwd = $repository->encodePassword($data['pwd']);
  364. $user->save();
  365. return app('json')->success('修改成功');
  366. }
  367. public function spread(UserRepository $userRepository)
  368. {
  369. $data = $this->request->params([
  370. ['spread_spid', 0],
  371. ['spread_code', null],
  372. ]);
  373. if (isset($data['spread_code']['id']) && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($data['spread_code']['id']))) {
  374. $data['spread_spid'] = $info['third_id'];
  375. }
  376. $userRepository->bindSpread($this->request->userInfo(), intval($data['spread_spid']));
  377. return app('json')->success();
  378. }
  379. /**
  380. * 注册账号
  381. * @param UserAuthValidate $validate
  382. * @param UserRepository $repository
  383. * @return \think\response\Json
  384. * @author Qinii
  385. * @day 5/27/21
  386. */
  387. public function register(UserAuthValidate $validate, UserRepository $repository)
  388. {
  389. $data = $this->request->params(['phone', 'sms_code', 'spread', 'pwd', 'auth_token', ['user_type', 'h5']]);
  390. $validate->check($data);
  391. $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'login');
  392. // if (!$sms_code)
  393. // return app('json')->fail('验证码不正确');
  394. $user = $repository->accountByUser($data['phone']);
  395. if ($user) return app('json')->fail('用户已存在');
  396. $auth = $this->parseAuthToken($data['auth_token']);
  397. $user = $repository->registr($data['phone'], $data['pwd'], $data['user_type']);
  398. if ($auth) {
  399. $repository->syncBaseAuth($auth, $user);
  400. }
  401. $user = $repository->mainUser($user);
  402. $repository->bindSpread($user, intval($data['spread']));
  403. $tokenInfo = $repository->createToken($user);
  404. $repository->loginAfter($user);
  405. return app('json')->success($repository->returnToken($user, $tokenInfo));
  406. }
  407. private function parseAuthToken($authToken)
  408. {
  409. $auth = Cache::get('u_try' . $authToken);
  410. $auth && Cache::delete('u_try' . $authToken);
  411. return $auth;
  412. }
  413. private function authInfo($auth, $createUser = false)
  414. {
  415. if (!in_array($auth['type'] ?? '', ['wechat', 'routine', 'apple', 'app_wechat']) || !isset($auth['auth']))
  416. throw new ValidateException('授权信息类型有误');
  417. $data = $auth['auth'];
  418. if ($auth['type'] === 'routine') {
  419. $code = $data['code'] ?? '';
  420. $userInfoCong = Cache::get('eb_api_code_' . $code);
  421. if (!$code && !$userInfoCong)
  422. throw new ValidateException('授权失败,参数有误');
  423. $miniProgramService = MiniProgramService::create();
  424. if ($code && !$userInfoCong) {
  425. try {
  426. $userInfoCong = $miniProgramService->getUserInfo($code);
  427. Cache::set('eb_api_code_' . $code, $userInfoCong, 86400);
  428. } catch (Exception $e) {
  429. throw new ValidateException('获取session_key失败,请检查您的配置!' . $e->getMessage());
  430. }
  431. }
  432. // try {
  433. // //解密获取用户信息
  434. // $userInfo = $miniProgramService->encryptor($userInfoCong['session_key'], $data['iv'], $data['encryptedData']);
  435. // } catch (Exception $e) {
  436. // if ($e->getCode() == '-41003') throw new ValidateException('获取会话密匙失败'.$e->getMessage());
  437. // throw $e;
  438. // }
  439. $userInfo = [];
  440. // if (!$userInfo) throw new ValidateException('openid获取失败');
  441. if (!isset($userInfo['openId'])) $userInfo['openId'] = $userInfoCong['openid'] ?? '';
  442. $userInfo['unionId'] = $userInfoCong['unionid'] ?? $userInfo['unionId'] ?? '';
  443. if (!$userInfo['openId']) throw new ValidateException('openid获取失败');
  444. /** @var WechatUserRepository $make */
  445. $make = app()->make(WechatUserRepository::class);
  446. $user = $make->syncRoutineUser($userInfo['openId'], $userInfo, $createUser);
  447. if (!$user)
  448. throw new ValidateException('授权失败');
  449. return $user;
  450. } else if ($auth['type'] === 'wechat') {
  451. $request = $this->request;
  452. $oauth = WechatService::create()->getApplication()->oauth;
  453. $oauth->setRequest(new Request($data, $data, [], [], [], $request->server(), $request->getContent()));
  454. try {
  455. $wechatInfo = $oauth->user()->getOriginal();
  456. } catch (Exception $e) {
  457. throw new ValidateException('授权失败[001]');
  458. }
  459. if (!isset($wechatInfo['nickname'])) {
  460. throw new ValidateException('授权失败[002]');
  461. }
  462. /** @var WechatUserRepository $make */
  463. $make = app()->make(WechatUserRepository::class);
  464. $user = $make->syncUser($wechatInfo['openid'], $wechatInfo, false, $createUser);
  465. if (!$user)
  466. throw new ValidateException('授权失败[003]');
  467. return $user;
  468. } else if ($auth['type'] === 'app_wechat') {
  469. $oauth = WechatService::create()->getApplication()->oauth;
  470. try {
  471. $wechatInfo = $oauth->user(new AccessToken(['access_token' => $data['code'], 'openid' => $data['openid']]))->getOriginal();
  472. } catch (Exception $e) {
  473. throw new ValidateException('授权失败[001]' . $e->getMessage());
  474. }
  475. $user = app()->make(WechatUserRepository::class)->syncAppUser($wechatInfo['unionid'], $wechatInfo, 'App', $createUser);
  476. if (!$user)
  477. throw new ValidateException('授权失败');
  478. return $user;
  479. } else if ($auth['type'] === 'apple') {
  480. $identityToken = $data['userInfo']['identityToken'];
  481. $tks = explode('.', $identityToken);
  482. if (count($tks) != 3) {
  483. throw new ValidateException('Wrong number of segments');
  484. }
  485. list($headb64, $bodyb64, $cryptob64) = $tks;
  486. if (null === ($payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64)))) {
  487. throw new ValidateException('Invalid header encoding');
  488. }
  489. if ($payload->sub != $data['openId']) {
  490. throw new ValidateException('授权失败');
  491. }
  492. $user = app()->make(WechatUserRepository::class)->syncAppUser($data['openId'], [
  493. 'nickName' => (string)$data['nickname'] ?: '用户' . strtoupper(substr(md5(time()), 0, 12))
  494. ], 'App', $createUser);
  495. if (!$user)
  496. throw new ValidateException('授权失败');
  497. return $user;
  498. }
  499. }
  500. /**
  501. * @return \think\response\Json
  502. * @author Qinii
  503. * @day 2023/11/9
  504. */
  505. public function authLogin()
  506. {
  507. $auth = $this->request->param('auth');
  508. $users = $this->authInfo($auth, !systemConfig('is_phone_login'));
  509. if (!$users)
  510. return app('json')->fail('授权失败');
  511. $authInfo = $users[0];
  512. $userRepository = app()->make(UserRepository::class);
  513. $user = $users[1] ?? $userRepository->wechatUserIdBytUser($authInfo['wechat_user_id']);
  514. $code = (int)($auth['auth']['spread_code']['id'] ?? $auth['auth']['spread_code'] ?? '');
  515. //获取是否有扫码进小程序
  516. if ($code && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($code))) {
  517. $auth['auth']['spread'] = $info['third_id'];
  518. }
  519. if (!$user) {
  520. $uni = uniqid(true, false) . random_int(1, 100000000);
  521. $key = 'U' . md5(time() . $uni);
  522. Cache::set('u_try' . $key, ['id' => $authInfo['wechat_user_id'], 'type' => $authInfo['user_type'], 'spread' => $auth['auth']['spread'] ?? 0], 3600);
  523. $wechat_phone_switch = systemConfig('wechat_phone_switch');
  524. return app('json')->status(201, compact('key','wechat_phone_switch'));
  525. }
  526. if ($auth['auth']['spread'] ?? 0) {
  527. $userRepository->bindSpread($user, (int)($auth['auth']['spread']));
  528. }
  529. $tokenInfo = $userRepository->createToken($user);
  530. $userRepository->loginAfter($user);
  531. return app('json')->status(200, $userRepository->returnToken($user, $tokenInfo));
  532. }
  533. /**
  534. * 查询小程序是否需要绑定手机好 以及绑定手机号的方式
  535. * @return \think\response\Json
  536. * @author Qinii
  537. * @day 2023/11/10'
  538. */
  539. public function mpLoginType()
  540. {
  541. $code = $this->request->param('code');
  542. if (!$code) return app('json')->fail('请获取code参数');
  543. $spread = $this->request->param('spread',0);
  544. $data = app()->make(WechatUserRepository::class)->mpLoginType($code,$spread);
  545. return app('json')->success($data);
  546. }
  547. /**
  548. * App微信登陆
  549. * @param Request $request
  550. * @return mixed
  551. */
  552. public function appAuth()
  553. {
  554. $data = $this->request->params(['userInfo']);
  555. if (systemConfig('is_phone_login') === '1') {
  556. return app('json')->fail('请绑定手机号');
  557. }
  558. $user = app()->make(WechatUserRepository::class)->syncAppUser($data['userInfo']['unionId'], $data['userInfo']);
  559. if (!$user)
  560. return app('json')->fail('授权失败');
  561. /** @var UserRepository $make */
  562. $userRepository = app()->make(UserRepository::class);
  563. $user[1] = $userRepository->mainUser($user[1]);
  564. $tokenInfo = $userRepository->createToken($user[1]);
  565. $userRepository->loginAfter($user[1]);
  566. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  567. }
  568. public function getMerCertificate($merId)
  569. {
  570. $merId = (int)$merId;
  571. $data = $this->request->params(['key', 'code']);
  572. if (!$this->checkCaptcha($data['key'], $data['code']))
  573. return app('json')->fail('验证码输入有误');
  574. $certificate = merchantConfig($merId, 'mer_certificate') ?: [];
  575. if (!count($certificate))
  576. return app('json')->fail('该商户未上传证书');
  577. return app('json')->success($certificate);
  578. }
  579. public function appleAuth()
  580. {
  581. $data = $this->request->params(['openId', 'nickname']);
  582. if (systemConfig('is_phone_login') === '1') {
  583. return app('json')->fail('请绑定手机号');
  584. }
  585. $user = app()->make(WechatUserRepository::class)->syncAppUser($data['openId'], [
  586. 'nickName' => (string)$data['nickname'] ?: '用户' . strtoupper(substr(md5(time()), 0, 12))
  587. ], 'apple');
  588. if (!$user)
  589. return app('json')->fail('授权失败');
  590. /** @var UserRepository $make */
  591. $userRepository = app()->make(UserRepository::class);
  592. $user[1] = $userRepository->mainUser($user[1]);
  593. $tokenInfo = $userRepository->createToken($user[1]);
  594. $userRepository->loginAfter($user[1]);
  595. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  596. }
  597. /**
  598. * 注销账号
  599. */
  600. public function cancel()
  601. {
  602. $userRepository = app()->make(UserRepository::class);
  603. $user = $this->request->userInfo();
  604. $order = app()->make(StoreOrderRepository::class)->search(['uid' => $user['uid'], 'paid' => 1])->where('StoreOrder.status', 0)->count();
  605. $refund = app()->make(StoreRefundOrderRepository::class)->search(['uid' => $user['uid'], 'type' => 1])->count();
  606. $key = $this->request->param('key');
  607. $flag = false;
  608. if ($user->now_money > 0 || $user->integral > 0 || $order > 0 || $refund > 0) {
  609. $flag = true;
  610. if (!$key) {
  611. $uni = uniqid(true, false) . random_int(1, 100000000);
  612. $key = 'L' . md5(time() . $uni);
  613. Cache::set('u_out' . $user['uid'], $key, 600);
  614. return app('json')->status(201, '该账号下有未完成业务,注销后不可恢复,您确定继续注销?', compact('key'));
  615. }
  616. }
  617. if ($flag && (!$key || (Cache::get('u_out' . $user['uid']) != $key))) {
  618. return app('json')->fail('操作超时');
  619. }
  620. $userRepository->cancel($user);
  621. $userRepository->clearToken($user);
  622. return app('json')->status(200, '注销成功');
  623. }
  624. /**
  625. * 通过小程序组件,获取小程序绑定手机号
  626. * @return \think\response\Json
  627. * @author Qinii
  628. * @day 2023/11/9
  629. */
  630. public function mpPhone()
  631. {
  632. $code = $this->request->param('code');
  633. $auth_token = $this->request->param('auth_token');
  634. $iv = $this->request->param('iv');
  635. $encryptedData = $this->request->param('encryptedData');
  636. $miniProgramService = MiniProgramService::create();
  637. $userInfoCong = Cache::get('eb_api_code_' . $code);
  638. if (!$code && !$userInfoCong)
  639. throw new ValidateException('授权失败,参数有误');
  640. if ($code && !$userInfoCong) {
  641. try {
  642. $userInfoCong = $miniProgramService->getUserInfo($code);
  643. Cache::set('eb_api_code_' . $code, $userInfoCong, 86400);
  644. } catch (Exception $e) {
  645. throw new ValidateException('获取session_key失败,请检查您的配置!');
  646. }
  647. }
  648. $session_key = $userInfoCong['session_key'];
  649. $data = $miniProgramService->encryptor($session_key, $iv, $encryptedData);
  650. $userRepository = app()->make(UserRepository::class);
  651. $phone = $data['purePhoneNumber'];
  652. $user = $userRepository->accountByUser($phone);
  653. // if($user && $auth_token){
  654. // return app('json')->fail('用户已存在');
  655. // }
  656. $auth = $this->parseAuthToken($auth_token);
  657. if ($user && $auth) {
  658. $userRepository->syncBaseAuth($auth, $user);
  659. } else if (!$user) {
  660. if (!$auth) {
  661. return app('json')->fail('操作超时');
  662. }
  663. $wechatUser = app()->make(WechatUserRepository::class)->get($auth['id']);
  664. $user = $userRepository->syncWechatUser($wechatUser, 'routine');
  665. $user->phone = $phone;
  666. $user->account = $phone;
  667. $user->save();
  668. if ($auth['spread']) {
  669. $userRepository->bindSpread($user,(int)$auth['spread']);
  670. }
  671. }
  672. $tokenInfo = $userRepository->createToken($user);
  673. $userRepository->loginAfter($user);
  674. return app('json')->success($userRepository->returnToken($user, $tokenInfo));
  675. }
  676. /**
  677. * @return mixed
  678. */
  679. public function ajcaptcha()
  680. {
  681. $captchaType = $this->request->param('captchaType', 'clickWord');
  682. if (!$captchaType) return app('json')->fail('请输入类型');
  683. return app('json')->success(aj_captcha_create($captchaType));
  684. }
  685. /**
  686. * 一次验证
  687. * @return mixed
  688. */
  689. public function ajcheck()
  690. {
  691. $token = $this->request->param('token', '');
  692. $pointJson = $this->request->param('pointJson', '');
  693. $captchaType = $this->request->param('captchaType', 'clickWord');
  694. try {
  695. aj_captcha_check_one($captchaType, $token, $pointJson);
  696. return app('json')->success();
  697. } catch (\Throwable $e) {
  698. return app('json')->fail($e->getMessage());
  699. }
  700. }
  701. }