LoginController.php 16 KB

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