LoginController.php 14 KB

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