LoginController.php 16 KB

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