LoginController.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\api\controller\v1;
  12. use app\Request;
  13. use app\services\message\notice\SmsService;
  14. use app\services\wechat\WechatServices;
  15. use think\facade\Cache;
  16. use app\jobs\TaskJob;
  17. use think\facade\Config;
  18. use crmeb\services\CacheService;
  19. use app\services\user\LoginServices;
  20. use think\exception\ValidateException;
  21. use app\api\validate\user\RegisterValidates;
  22. /**
  23. * 微信小程序授权类
  24. * Class AuthController
  25. * @package app\api\controller
  26. */
  27. class LoginController
  28. {
  29. protected $services;
  30. /**
  31. * LoginController constructor.
  32. * @param LoginServices $services
  33. */
  34. public function __construct(LoginServices $services)
  35. {
  36. $this->services = $services;
  37. }
  38. /**
  39. * H5账号登陆
  40. * @param Request $request
  41. * @return mixed
  42. * @throws \think\db\exception\DataNotFoundException
  43. * @throws \think\db\exception\ModelNotFoundException
  44. * @throws \think\exception\DbException
  45. */
  46. public function login(Request $request)
  47. {
  48. [$account, $password, $spread] = $request->postMore([
  49. 'account', 'password', 'spread'
  50. ], true);
  51. if (!$account || !$password) {
  52. return app('json')->fail(410000);
  53. }
  54. if (count($password) > 32 || count($password) < 6) {
  55. return app('json')->fail(400762);
  56. }
  57. return app('json')->success(410001, $this->services->login($account, $password, $spread));
  58. }
  59. /**
  60. * 退出登录
  61. * @param Request $request
  62. * @return mixed
  63. */
  64. public function logout(Request $request)
  65. {
  66. $key = trim(ltrim($request->header(Config::get('cookie.token_name')), 'Bearer'));
  67. CacheService::delete(md5($key));
  68. return app('json')->success(410002);
  69. }
  70. /**
  71. * 获取发送验证码key
  72. * @return mixed
  73. */
  74. public function verifyCode()
  75. {
  76. $unique = password_hash(uniqid(true), PASSWORD_BCRYPT);
  77. Cache::set('sms.key.' . $unique, 0, 300);
  78. $time = sys_config('verify_expire_time', 1);
  79. return app('json')->success(['key' => $unique, 'expire_time' => $time]);
  80. }
  81. /**
  82. * 获取图片验证码
  83. * @param Request $request
  84. * @return \think\Response
  85. */
  86. public function captcha(Request $request)
  87. {
  88. ob_clean();
  89. $rep = captcha();
  90. $key = app('session')->get('captcha.key');
  91. $uni = $request->get('key');
  92. if ($uni) {
  93. Cache::set('sms.key.cap.' . $uni, $key, 300);
  94. }
  95. return $rep;
  96. }
  97. /**
  98. * 验证验证码是否正确
  99. * @param $uni
  100. * @param string $code
  101. * @return bool
  102. * @throws \Psr\SimpleCache\InvalidArgumentException
  103. */
  104. protected function checkCaptcha($uni, string $code): bool
  105. {
  106. $cacheName = 'sms.key.cap.' . $uni;
  107. if (!Cache::has($cacheName)) {
  108. return false;
  109. }
  110. $key = Cache::get($cacheName);
  111. $code = mb_strtolower($code, 'UTF-8');
  112. $res = password_verify($code, $key);
  113. if ($res) {
  114. Cache::delete($cacheName);
  115. }
  116. return $res;
  117. }
  118. /**
  119. * 验证码发送
  120. * @param Request $request
  121. * @param SmsService $services
  122. * @return mixed
  123. */
  124. public function verify(Request $request, SmsService $services)
  125. {
  126. [$phone, $type, $key, $captchaType, $captchaVerification] = $request->postMore([
  127. ['phone', 0],
  128. ['type', ''],
  129. ['key', ''],
  130. ['captchaType', ''],
  131. ['captchaVerification', ''],
  132. ], true);
  133. $keyName = 'sms.key.' . $key;
  134. $nowKey = 'sms.' . date('YmdHi');
  135. if (!Cache::has($keyName)) {
  136. return app('json')->fail(410003);
  137. }
  138. $total = 1;
  139. if (Cache::has($nowKey)) {
  140. $total = Cache::get($nowKey);
  141. if ($total > Config::get('sms.maxMinuteCount', 20))
  142. return app('json')->success(410006);
  143. }
  144. //二次验证
  145. try {
  146. aj_captcha_check_two($captchaType, $captchaVerification);
  147. } catch (\Throwable $e) {
  148. return app('json')->fail($e->getError());
  149. }
  150. try {
  151. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  152. } catch (ValidateException $e) {
  153. return app('json')->fail($e->getError());
  154. }
  155. $time = sys_config('verify_expire_time', 1);
  156. $smsCode = $this->services->verify($services, $phone, $type, $time, app()->request->ip());
  157. if ($smsCode) {
  158. CacheService::set('code_' . $phone, $smsCode, $time * 60);
  159. Cache::set($nowKey, $total, 61);
  160. return app('json')->success(410007);
  161. } else {
  162. return app('json')->fail(410008);
  163. }
  164. }
  165. /**
  166. * H5注册新用户
  167. * @param Request $request
  168. * @return mixed
  169. * @throws \think\db\exception\DataNotFoundException
  170. * @throws \think\db\exception\DbException
  171. * @throws \think\db\exception\ModelNotFoundException
  172. */
  173. public function register(Request $request)
  174. {
  175. [$account, $captcha, $password, $spread] = $request->postMore([['account', ''], ['captcha', ''], ['password', ''], ['spread', 0]], true);
  176. try {
  177. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  178. } catch (ValidateException $e) {
  179. return app('json')->fail($e->getError());
  180. }
  181. if (count($password) > 32 || count($password) < 6) {
  182. return app('json')->fail(400762);
  183. }
  184. $verifyCode = CacheService::get('code_' . $account);
  185. if (!$verifyCode)
  186. return app('json')->fail(410009);
  187. $verifyCode = substr($verifyCode, 0, 6);
  188. if ($verifyCode != $captcha)
  189. return app('json')->fail(410010);
  190. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  191. return app('json')->fail(410011);
  192. if (md5($password) == md5('123456')) return app('json')->fail(410012);
  193. $registerStatus = $this->services->register($account, $password, $spread, 'h5');
  194. if ($registerStatus) {
  195. return app('json')->success(410013);
  196. }
  197. return app('json')->fail(410014);
  198. }
  199. /**
  200. * 密码修改
  201. * @param Request $request
  202. * @return mixed
  203. * @throws \think\db\exception\DataNotFoundException
  204. * @throws \think\db\exception\DbException
  205. * @throws \think\db\exception\ModelNotFoundException
  206. */
  207. public function reset(Request $request)
  208. {
  209. [$account, $captcha, $password] = $request->postMore([['account', ''], ['captcha', ''], ['password', '']], true);
  210. try {
  211. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  212. } catch (ValidateException $e) {
  213. return app('json')->fail($e->getError());
  214. }
  215. if (count($password) > 32 || count($password) < 6) {
  216. return app('json')->fail(400762);
  217. }
  218. $verifyCode = CacheService::get('code_' . $account);
  219. if (!$verifyCode)
  220. return app('json')->fail(410009);
  221. $verifyCode = substr($verifyCode, 0, 6);
  222. if ($verifyCode != $captcha) {
  223. return app('json')->fail(410010);
  224. }
  225. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  226. return app('json')->fail(410011);
  227. if ($password == '123456') return app('json')->fail(410012);
  228. $resetStatus = $this->services->reset($account, $password);
  229. if ($resetStatus) return app('json')->success(100001);
  230. return app('json')->fail(100007);
  231. }
  232. /**
  233. * 手机号登录
  234. * @param Request $request
  235. * @return mixed
  236. * @throws \think\db\exception\DataNotFoundException
  237. * @throws \think\db\exception\ModelNotFoundException
  238. * @throws \think\exception\DbException
  239. */
  240. public function mobile(Request $request)
  241. {
  242. [$phone, $captcha, $spread] = $request->postMore([['phone', ''], ['captcha', ''], ['spread', 0]], true);
  243. //验证手机号
  244. try {
  245. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  246. } catch (ValidateException $e) {
  247. return app('json')->fail($e->getError());
  248. }
  249. //验证验证码
  250. $verifyCode = CacheService::get('code_' . $phone);
  251. if (!$verifyCode)
  252. return app('json')->fail(410009);
  253. $verifyCode = substr($verifyCode, 0, 6);
  254. if ($verifyCode != $captcha) {
  255. return app('json')->fail(410010);
  256. }
  257. $user_type = $request->getFromType() ? $request->getFromType() : 'h5';
  258. $token = $this->services->mobile($phone, $spread, $user_type);
  259. if ($token) {
  260. CacheService::delete('code_' . $phone);
  261. return app('json')->success(410001, $token);
  262. } else {
  263. return app('json')->fail(410002);
  264. }
  265. }
  266. /**
  267. * H5切换登陆
  268. * @param Request $request
  269. * @return mixed
  270. * @throws \think\db\exception\DataNotFoundException
  271. * @throws \think\db\exception\ModelNotFoundException
  272. * @throws \think\exception\DbException
  273. */
  274. public function switch_h5(Request $request)
  275. {
  276. $from = $request->post('from', 'wechat');
  277. $user = $request->user();
  278. $token = $this->services->switchAccount($user, $from);
  279. if ($token) {
  280. $token['userInfo'] = $user;
  281. return app('json')->success(410001, $token);
  282. } else
  283. return app('json')->fail(410002);
  284. }
  285. /**
  286. * 绑定手机号
  287. * @param Request $request
  288. * @return mixed
  289. * @throws \think\db\exception\DataNotFoundException
  290. * @throws \think\db\exception\ModelNotFoundException
  291. * @throws \think\exception\DbException
  292. */
  293. public function binding_phone(Request $request)
  294. {
  295. list($phone, $captcha, $key) = $request->postMore([
  296. ['phone', ''],
  297. ['captcha', ''],
  298. ['key', '']
  299. ], true);
  300. //验证手机号
  301. try {
  302. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  303. } catch (ValidateException $e) {
  304. return app('json')->fail($e->getError());
  305. }
  306. if (!$key) {
  307. return app('json')->fail(100100);
  308. }
  309. if (!$phone) {
  310. return app('json')->fail(410015);
  311. }
  312. //验证验证码
  313. $verifyCode = CacheService::get('code_' . $phone);
  314. if (!$verifyCode)
  315. return app('json')->fail(410009);
  316. $verifyCode = substr($verifyCode, 0, 6);
  317. if ($verifyCode != $captcha) {
  318. return app('json')->fail(410010);
  319. }
  320. $re = $this->services->bindind_phone($phone, $key);
  321. if ($re) {
  322. CacheService::delete('code_' . $phone);
  323. return app('json')->success(410016, $re);
  324. } else
  325. return app('json')->fail(410017);
  326. }
  327. /**
  328. * 绑定手机号
  329. * @param Request $request
  330. * @return mixed
  331. * @throws \think\db\exception\DataNotFoundException
  332. * @throws \think\db\exception\ModelNotFoundException
  333. * @throws \think\exception\DbException
  334. */
  335. public function user_binding_phone(Request $request)
  336. {
  337. list($phone, $captcha, $step) = $request->postMore([
  338. ['phone', ''],
  339. ['captcha', ''],
  340. ['step', 0]
  341. ], true);
  342. //验证手机号
  343. try {
  344. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  345. } catch (ValidateException $e) {
  346. return app('json')->fail($e->getError());
  347. }
  348. if (!$step) {
  349. //验证验证码
  350. $verifyCode = CacheService::get('code_' . $phone);
  351. if (!$verifyCode)
  352. return app('json')->fail(410009);
  353. $verifyCode = substr($verifyCode, 0, 6);
  354. if ($verifyCode != $captcha)
  355. return app('json')->fail(410010);
  356. }
  357. $uid = (int)$request->uid();
  358. $re = $this->services->userBindindPhone($uid, $phone, $step);
  359. if ($re) {
  360. CacheService::delete('code_' . $phone);
  361. return app('json')->success($re['msg'] ?? 410016, $re['data'] ?? []);
  362. } else
  363. return app('json')->fail(410017);
  364. }
  365. public function update_binding_phone(Request $request)
  366. {
  367. [$phone, $captcha] = $request->postMore([
  368. ['phone', ''],
  369. ['captcha', ''],
  370. ], true);
  371. //验证手机号
  372. try {
  373. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  374. } catch (ValidateException $e) {
  375. return app('json')->fail($e->getError());
  376. }
  377. //验证验证码
  378. $verifyCode = CacheService::get('code_' . $phone);
  379. if (!$verifyCode)
  380. return app('json')->fail(410009);
  381. $verifyCode = substr($verifyCode, 0, 6);
  382. if ($verifyCode != $captcha)
  383. return app('json')->fail(410010);
  384. $uid = (int)$request->uid();
  385. $re = $this->services->updateBindindPhone($uid, $phone);
  386. if ($re) {
  387. CacheService::delete('code_' . $phone);
  388. return app('json')->success($re['msg'] ?? 100001, $re['data'] ?? []);
  389. } else
  390. return app('json')->fail(100007);
  391. }
  392. /**
  393. * 设置扫描二维码状态
  394. * @param string $code
  395. * @return mixed
  396. */
  397. public function setLoginKey(string $code)
  398. {
  399. if (!$code) {
  400. return app('json')->fail(410020);
  401. }
  402. $cacheCode = CacheService::get($code);
  403. if ($cacheCode === false || $cacheCode === null) {
  404. return app('json')->fail(410021);
  405. }
  406. CacheService::set($code, '0', 600);
  407. return app('json')->success();
  408. }
  409. /**
  410. * apple快捷登陆
  411. * @param Request $request
  412. * @param WechatServices $services
  413. * @return mixed
  414. * @throws \Psr\SimpleCache\InvalidArgumentException
  415. * @throws \think\db\exception\DataNotFoundException
  416. * @throws \think\db\exception\ModelNotFoundException
  417. */
  418. public function appleLogin(Request $request, WechatServices $services)
  419. {
  420. [$openId, $phone, $email, $captcha] = $request->postMore([
  421. ['openId', ''],
  422. ['phone', ''],
  423. ['email', ''],
  424. ['captcha', '']
  425. ], true);
  426. if ($phone) {
  427. if (!$captcha) {
  428. return app('json')->fail(410004);
  429. }
  430. //验证验证码
  431. $verifyCode = CacheService::get('code_' . $phone);
  432. if (!$verifyCode)
  433. return app('json')->fail(410009);
  434. $verifyCode = substr($verifyCode, 0, 6);
  435. if ($verifyCode != $captcha) {
  436. CacheService::delete('code_' . $phone);
  437. return app('json')->fail(410010);
  438. }
  439. }
  440. if ($email == '') $email = substr(md5($openId), 0, 12);
  441. $userInfo = [
  442. 'openId' => $openId,
  443. 'unionid' => '',
  444. 'avatarUrl' => sys_config('h5_avatar'),
  445. 'nickName' => $email,
  446. ];
  447. $token = $services->appAuth($userInfo, $phone, 'apple');
  448. if ($token) {
  449. return app('json')->success(410001, $token);
  450. } else if ($token === false) {
  451. return app('json')->success(410001, ['isbind' => true]);
  452. } else {
  453. return app('json')->fail(410019);
  454. }
  455. }
  456. /**
  457. * 滑块验证
  458. * @return mixed
  459. */
  460. public function ajcaptcha(Request $request)
  461. {
  462. $captchaType = $request->get('captchaType');
  463. return app('json')->success(aj_captcha_create($captchaType));
  464. }
  465. /**
  466. * 一次验证
  467. * @return mixed
  468. */
  469. public function ajcheck(Request $request)
  470. {
  471. [$token, $pointJson, $captchaType] = $request->postMore([
  472. ['token', ''],
  473. ['pointJson', ''],
  474. ['captchaType', ''],
  475. ], true);
  476. try {
  477. aj_captcha_check_one($captchaType, $token, $pointJson);
  478. return app('json')->success();
  479. } catch (\Throwable $e) {
  480. return app('json')->fail(400336);
  481. }
  482. }
  483. }