LoginController.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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. namespace app\api\controller\v1;
  12. use app\Request;
  13. use app\services\wechat\WechatServices;
  14. use think\facade\Cache;
  15. use app\jobs\TaskJob;
  16. use think\facade\Config;
  17. use crmeb\services\CacheService;
  18. use app\services\user\LoginServices;
  19. use think\exception\ValidateException;
  20. use app\api\validate\user\RegisterValidates;
  21. use app\services\message\sms\SmsSendServices;
  22. /**微信小程序授权类
  23. * Class AuthController
  24. * @package app\api\controller
  25. */
  26. class LoginController
  27. {
  28. protected $services = NUll;
  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('请输入账号和密码');
  53. }
  54. return app('json')->success('登录成功', $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('成功');
  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. return $rep;
  82. }
  83. /**
  84. * 验证验证码是否正确
  85. *
  86. * @param $uni
  87. * @param string $code
  88. * @return bool
  89. * @throws \Psr\SimpleCache\InvalidArgumentException
  90. */
  91. protected function checkCaptcha($uni, string $code): bool
  92. {
  93. $cacheName = 'sms.key.cap.' . $uni;
  94. if (!Cache::has($cacheName)) {
  95. return false;
  96. }
  97. $key = Cache::get($cacheName);
  98. $code = mb_strtolower($code, 'UTF-8');
  99. $res = password_verify($code, $key);
  100. if ($res) {
  101. Cache::delete($cacheName);
  102. }
  103. return $res;
  104. }
  105. /**
  106. * 验证码发送
  107. * @param Request $request
  108. * @return mixed
  109. */
  110. public function verify(Request $request, SmsSendServices $services)
  111. {
  112. [$phone, $type, $key, $code] = $request->postMore([['phone', 0], ['type', ''], ['key', ''], ['code', '']], true);
  113. $keyName = 'sms.key.' . $key;
  114. $nowKey = 'sms.' . date('YmdHi');
  115. if (!Cache::has($keyName))
  116. return app('json')->make(401, '发送验证码失败,请刷新页面重新获取');
  117. if (($num = Cache::get($keyName)) > 2) {
  118. if (!$code)
  119. return app('json')->make(402, '请输入验证码');
  120. if (!$this->checkCaptcha($key, $code))
  121. return app('json')->fail('验证码输入有误');
  122. }
  123. $total = 1;
  124. if ($has = Cache::has($nowKey)) {
  125. $total = Cache::get($nowKey);
  126. if ($total > Config::get('sms.maxMinuteCount', 20))
  127. return app('json')->success('已发送');
  128. }
  129. try {
  130. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  131. } catch (ValidateException $e) {
  132. return app('json')->fail($e->getError());
  133. }
  134. $time = sys_config('verify_expire_time', 1);
  135. $smsCode = $this->services->verify($services, $phone, $type, $time, app()->request->ip());
  136. if ($smsCode) {
  137. CacheService::set('code_' . $phone, $smsCode, $time * 60);
  138. Cache::set($keyName, $num + 1, 300);
  139. Cache::set($nowKey, $total, 61);
  140. return app('json')->success('发送成功');
  141. } else {
  142. return app('json')->fail('发送失败');
  143. }
  144. }
  145. /**
  146. * H5注册新用户
  147. * @param Request $request
  148. * @return mixed
  149. */
  150. public function register(Request $request)
  151. {
  152. [$account, $captcha, $password, $spread] = $request->postMore([['account', ''], ['captcha', ''], ['password', ''], ['spread', 0]], true);
  153. try {
  154. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  155. } catch (ValidateException $e) {
  156. return app('json')->fail($e->getError());
  157. }
  158. $verifyCode = CacheService::get('code_' . $account);
  159. if (!$verifyCode)
  160. return app('json')->fail('请先获取验证码');
  161. $verifyCode = substr($verifyCode, 0, 6);
  162. if ($verifyCode != $captcha)
  163. return app('json')->fail('验证码错误');
  164. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  165. return app('json')->fail('密码必须是在6到16位之间');
  166. if (md5($password) == md5('123456')) return app('json')->fail('密码太过简单,请输入较为复杂的密码');
  167. $registerStatus = $this->services->register($account, $password, $spread, 'h5');
  168. if ($registerStatus) {
  169. return app('json')->success('注册成功');
  170. }
  171. return app('json')->fail('注册失败');
  172. }
  173. /**
  174. * 密码修改
  175. * @param Request $request
  176. * @return mixed
  177. */
  178. public function reset(Request $request)
  179. {
  180. [$account, $captcha, $password] = $request->postMore([['account', ''], ['captcha', ''], ['password', '']], true);
  181. try {
  182. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  183. } catch (ValidateException $e) {
  184. return app('json')->fail($e->getError());
  185. }
  186. $verifyCode = CacheService::get('code_' . $account);
  187. if (!$verifyCode)
  188. return app('json')->fail('请先获取验证码');
  189. $verifyCode = substr($verifyCode, 0, 6);
  190. if ($verifyCode != $captcha) {
  191. return app('json')->fail('验证码错误');
  192. }
  193. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  194. return app('json')->fail('密码必须是在6到16位之间');
  195. if ($password == '123456') return app('json')->fail('密码太过简单,请输入较为复杂的密码');
  196. $resetStatus = $this->services->reset($account, $password);
  197. if ($resetStatus) return app('json')->success('修改成功');
  198. return app('json')->fail('修改失败');
  199. }
  200. /**
  201. * 手机号登录
  202. * @param Request $request
  203. * @return mixed
  204. * @throws \think\db\exception\DataNotFoundException
  205. * @throws \think\db\exception\ModelNotFoundException
  206. * @throws \think\exception\DbException
  207. */
  208. public function mobile(Request $request)
  209. {
  210. [$phone, $captcha, $spread] = $request->postMore([['phone', ''], ['captcha', ''], ['spread', 0]], true);
  211. //验证手机号
  212. try {
  213. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  214. } catch (ValidateException $e) {
  215. return app('json')->fail($e->getError());
  216. }
  217. //验证验证码
  218. $verifyCode = CacheService::get('code_' . $phone);
  219. if (!$verifyCode)
  220. return app('json')->fail('请先获取验证码');
  221. $verifyCode = substr($verifyCode, 0, 6);
  222. if ($verifyCode != $captcha) {
  223. return app('json')->fail('验证码错误');
  224. }
  225. $user_type = $request->getFromType() ? $request->getFromType() : 'h5';
  226. $token = $this->services->mobile($phone, $spread, $user_type);
  227. if ($token) {
  228. CacheService::delete('code_' . $phone);
  229. return app('json')->success('登录成功', $token);
  230. } else {
  231. return app('json')->fail('登录失败');
  232. }
  233. }
  234. /**
  235. * H5切换登陆
  236. * @param Request $request
  237. * @return mixed
  238. * @throws \think\db\exception\DataNotFoundException
  239. * @throws \think\db\exception\ModelNotFoundException
  240. * @throws \think\exception\DbException
  241. */
  242. public function switch_h5(Request $request)
  243. {
  244. $from = $request->post('from', 'wechat');
  245. $user = $request->user();
  246. $token = $this->services->switchAccount($user, $from);
  247. if ($token) {
  248. $token['userInfo'] = $user;
  249. return app('json')->success('登录成功', $token);
  250. } else
  251. return app('json')->fail('登录失败');
  252. }
  253. /**
  254. * 绑定手机号
  255. * @param Request $request
  256. * @return mixed
  257. * @throws \think\db\exception\DataNotFoundException
  258. * @throws \think\db\exception\ModelNotFoundException
  259. * @throws \think\exception\DbException
  260. */
  261. public function binding_phone(Request $request)
  262. {
  263. list($phone, $captcha, $key) = $request->postMore([
  264. ['phone', ''],
  265. ['captcha', ''],
  266. ['key', '']
  267. ], true);
  268. //验证手机号
  269. try {
  270. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  271. } catch (ValidateException $e) {
  272. return app('json')->fail($e->getError());
  273. }
  274. if (!$key) {
  275. return app('json')->fail('参数错误');
  276. }
  277. if (!$phone) {
  278. return app('json')->fail('请输入手机号');
  279. }
  280. //验证验证码
  281. $verifyCode = CacheService::get('code_' . $phone);
  282. if (!$verifyCode)
  283. return app('json')->fail('请先获取验证码');
  284. $verifyCode = substr($verifyCode, 0, 6);
  285. if ($verifyCode != $captcha) {
  286. return app('json')->fail('验证码错误');
  287. }
  288. $re = $this->services->bindind_phone($phone, $key);
  289. if ($re) {
  290. CacheService::delete('code_' . $phone);
  291. return app('json')->success('绑定成功', $re);
  292. } else
  293. return app('json')->fail('绑定失败');
  294. }
  295. /**
  296. * 绑定手机号
  297. * @param Request $request
  298. * @return mixed
  299. * @throws \think\db\exception\DataNotFoundException
  300. * @throws \think\db\exception\ModelNotFoundException
  301. * @throws \think\exception\DbException
  302. */
  303. public function user_binding_phone(Request $request)
  304. {
  305. list($phone, $captcha, $step) = $request->postMore([
  306. ['phone', ''],
  307. ['captcha', ''],
  308. ['step', 0]
  309. ], true);
  310. //验证手机号
  311. try {
  312. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  313. } catch (ValidateException $e) {
  314. return app('json')->fail($e->getError());
  315. }
  316. if (!$step) {
  317. //验证验证码
  318. $verifyCode = CacheService::get('code_' . $phone);
  319. if (!$verifyCode)
  320. return app('json')->fail('请先获取验证码');
  321. $verifyCode = substr($verifyCode, 0, 6);
  322. if ($verifyCode != $captcha)
  323. return app('json')->fail('验证码错误');
  324. }
  325. $uid = (int)$request->uid();
  326. $re = $this->services->userBindindPhone($uid, $phone, $step);
  327. if ($re) {
  328. CacheService::delete('code_' . $phone);
  329. return app('json')->success($re['msg'] ?? '绑定成功', $re['data'] ?? []);
  330. } else
  331. return app('json')->fail('绑定失败');
  332. }
  333. public function update_binding_phone(Request $request)
  334. {
  335. [$phone, $captcha] = $request->postMore([
  336. ['phone', ''],
  337. ['captcha', ''],
  338. ], true);
  339. //验证手机号
  340. try {
  341. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  342. } catch (ValidateException $e) {
  343. return app('json')->fail($e->getError());
  344. }
  345. //验证验证码
  346. $verifyCode = CacheService::get('code_' . $phone);
  347. if (!$verifyCode)
  348. return app('json')->fail('请先获取验证码');
  349. $verifyCode = substr($verifyCode, 0, 6);
  350. if ($verifyCode != $captcha)
  351. return app('json')->fail('验证码错误');
  352. $uid = (int)$request->uid();
  353. $re = $this->services->updateBindindPhone($uid, $phone);
  354. if ($re) {
  355. CacheService::delete('code_' . $phone);
  356. return app('json')->success($re['msg'] ?? '修改成功', $re['data'] ?? []);
  357. } else
  358. return app('json')->fail('修改失败');
  359. }
  360. /**
  361. * 设置扫描二维码状态
  362. * @param string $code
  363. * @return mixed
  364. */
  365. public function setLoginKey(string $code)
  366. {
  367. if (!$code) {
  368. return app('json')->fail('登录CODE不存在');
  369. }
  370. $cacheCode = CacheService::get($code);
  371. if ($cacheCode === false || $cacheCode === null) {
  372. return app('json')->fail('二维码已过期请重新扫描');
  373. }
  374. CacheService::set($code, '0', 600);
  375. return app('json')->success();
  376. }
  377. /**
  378. * apple快捷登陆
  379. * @param Request $request
  380. * @param WechatServices $services
  381. * @return mixed
  382. * @throws \Psr\SimpleCache\InvalidArgumentException
  383. * @throws \think\db\exception\DataNotFoundException
  384. * @throws \think\db\exception\ModelNotFoundException
  385. */
  386. public function appleLogin(Request $request, WechatServices $services)
  387. {
  388. [$openId, $phone, $email, $captcha] = $request->postMore([
  389. ['openId', ''],
  390. ['phone', ''],
  391. ['email', ''],
  392. ['captcha', '']
  393. ], true);
  394. if ($phone) {
  395. if (!$captcha) {
  396. return app('json')->fail('请输入验证码');
  397. }
  398. //验证验证码
  399. $verifyCode = CacheService::get('code_' . $phone);
  400. if (!$verifyCode)
  401. return app('json')->fail('请先获取验证码');
  402. $verifyCode = substr($verifyCode, 0, 6);
  403. if ($verifyCode != $captcha) {
  404. CacheService::delete('code_' . $phone);
  405. return app('json')->fail('验证码错误');
  406. }
  407. }
  408. $userInfo = [
  409. 'openId' => $openId,
  410. 'unionid' => '',
  411. 'avatarUrl' => sys_config('h5_avatar'),
  412. 'nickName' => $email,
  413. ];
  414. $token = $services->appAuth($userInfo, $phone, 'apple');
  415. if ($token) {
  416. return app('json')->success('登录成功', $token);
  417. } else if ($token === false) {
  418. return app('json')->success('登录成功', ['isbind' => true]);
  419. } else {
  420. return app('json')->fail('登陆失败');
  421. }
  422. }
  423. }