LoginController.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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\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, $code] = $request->postMore([['phone', 0], ['type', ''], ['key', ''], ['code', '']], true);
  114. $keyName = 'sms.key.' . $key;
  115. $nowKey = 'sms.' . date('YmdHi');
  116. if (!Cache::has($keyName))
  117. return app('json')->fail(410003);
  118. if (($num = Cache::get($keyName)) > 2) {
  119. if (!$code)
  120. return app('json')->fail(410004);
  121. if (!$this->checkCaptcha($key, $code))
  122. return app('json')->fail(410005);
  123. }
  124. $total = 1;
  125. if ($has = Cache::has($nowKey)) {
  126. $total = Cache::get($nowKey);
  127. if ($total > Config::get('sms.maxMinuteCount', 20))
  128. return app('json')->success(410006);
  129. }
  130. try {
  131. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  132. } catch (ValidateException $e) {
  133. return app('json')->fail($e->getError());
  134. }
  135. $time = sys_config('verify_expire_time', 1);
  136. $smsCode = $this->services->verify($services, $phone, $type, $time, app()->request->ip());
  137. if ($smsCode) {
  138. CacheService::set('code_' . $phone, $smsCode, $time * 60);
  139. Cache::set($keyName, $num + 1, 300);
  140. Cache::set($nowKey, $total, 61);
  141. return app('json')->success(410007);
  142. } else {
  143. return app('json')->fail(410008);
  144. }
  145. }
  146. /**
  147. * H5注册新用户
  148. * @param Request $request
  149. * @return mixed
  150. */
  151. public function register(Request $request)
  152. {
  153. [$account, $captcha, $password, $spread] = $request->postMore([['account', ''], ['captcha', ''], ['password', ''], ['spread', 0]], true);
  154. try {
  155. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  156. } catch (ValidateException $e) {
  157. return app('json')->fail($e->getError());
  158. }
  159. $verifyCode = CacheService::get('code_' . $account);
  160. if (!$verifyCode)
  161. return app('json')->fail(410009);
  162. $verifyCode = substr($verifyCode, 0, 6);
  163. if ($verifyCode != $captcha)
  164. return app('json')->fail(410010);
  165. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  166. return app('json')->fail(410011);
  167. if (md5($password) == md5('123456')) return app('json')->fail(410012);
  168. $registerStatus = $this->services->register($account, $password, $spread, 'h5');
  169. if ($registerStatus) {
  170. return app('json')->success(410013);
  171. }
  172. return app('json')->fail(410014);
  173. }
  174. /**
  175. * 密码修改
  176. * @param Request $request
  177. * @return mixed
  178. */
  179. public function reset(Request $request)
  180. {
  181. [$account, $captcha, $password] = $request->postMore([['account', ''], ['captcha', ''], ['password', '']], true);
  182. try {
  183. validate(RegisterValidates::class)->scene('register')->check(['account' => $account, 'captcha' => $captcha, 'password' => $password]);
  184. } catch (ValidateException $e) {
  185. return app('json')->fail($e->getError());
  186. }
  187. $verifyCode = CacheService::get('code_' . $account);
  188. if (!$verifyCode)
  189. return app('json')->fail(410009);
  190. $verifyCode = substr($verifyCode, 0, 6);
  191. if ($verifyCode != $captcha) {
  192. return app('json')->fail(410010);
  193. }
  194. if (strlen(trim($password)) < 6 || strlen(trim($password)) > 16)
  195. return app('json')->fail(410011);
  196. if ($password == '123456') return app('json')->fail(410012);
  197. $resetStatus = $this->services->reset($account, $password);
  198. if ($resetStatus) return app('json')->success(100001);
  199. return app('json')->fail(100007);
  200. }
  201. /**
  202. * 手机号登录
  203. * @param Request $request
  204. * @return mixed
  205. * @throws \think\db\exception\DataNotFoundException
  206. * @throws \think\db\exception\ModelNotFoundException
  207. * @throws \think\exception\DbException
  208. */
  209. public function mobile(Request $request)
  210. {
  211. [$phone, $captcha, $spread] = $request->postMore([['phone', ''], ['captcha', ''], ['spread', 0]], true);
  212. //验证手机号
  213. try {
  214. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  215. } catch (ValidateException $e) {
  216. return app('json')->fail($e->getError());
  217. }
  218. //验证验证码
  219. $verifyCode = CacheService::get('code_' . $phone);
  220. if (!$verifyCode)
  221. return app('json')->fail(410009);
  222. $verifyCode = substr($verifyCode, 0, 6);
  223. if ($verifyCode != $captcha) {
  224. return app('json')->fail(410010);
  225. }
  226. $user_type = $request->getFromType() ? $request->getFromType() : 'h5';
  227. $token = $this->services->mobile($phone, $spread, $user_type);
  228. if ($token) {
  229. CacheService::delete('code_' . $phone);
  230. return app('json')->success(410001, $token);
  231. } else {
  232. return app('json')->fail(410002);
  233. }
  234. }
  235. /**
  236. * H5切换登陆
  237. * @param Request $request
  238. * @return mixed
  239. * @throws \think\db\exception\DataNotFoundException
  240. * @throws \think\db\exception\ModelNotFoundException
  241. * @throws \think\exception\DbException
  242. */
  243. public function switch_h5(Request $request)
  244. {
  245. $from = $request->post('from', 'wechat');
  246. $user = $request->user();
  247. $token = $this->services->switchAccount($user, $from);
  248. if ($token) {
  249. $token['userInfo'] = $user;
  250. return app('json')->success(410001, $token);
  251. } else
  252. return app('json')->fail(410002);
  253. }
  254. /**
  255. * 绑定手机号
  256. * @param Request $request
  257. * @return mixed
  258. * @throws \think\db\exception\DataNotFoundException
  259. * @throws \think\db\exception\ModelNotFoundException
  260. * @throws \think\exception\DbException
  261. */
  262. public function binding_phone(Request $request)
  263. {
  264. list($phone, $captcha, $key) = $request->postMore([
  265. ['phone', ''],
  266. ['captcha', ''],
  267. ['key', '']
  268. ], true);
  269. //验证手机号
  270. try {
  271. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  272. } catch (ValidateException $e) {
  273. return app('json')->fail($e->getError());
  274. }
  275. if (!$key) {
  276. return app('json')->fail(100100);
  277. }
  278. if (!$phone) {
  279. return app('json')->fail(410015);
  280. }
  281. //验证验证码
  282. $verifyCode = CacheService::get('code_' . $phone);
  283. if (!$verifyCode)
  284. return app('json')->fail(410009);
  285. $verifyCode = substr($verifyCode, 0, 6);
  286. if ($verifyCode != $captcha) {
  287. return app('json')->fail(410010);
  288. }
  289. $re = $this->services->bindind_phone($phone, $key);
  290. if ($re) {
  291. CacheService::delete('code_' . $phone);
  292. return app('json')->success(410016, $re);
  293. } else
  294. return app('json')->fail(410017);
  295. }
  296. /**
  297. * 绑定手机号
  298. * @param Request $request
  299. * @return mixed
  300. * @throws \think\db\exception\DataNotFoundException
  301. * @throws \think\db\exception\ModelNotFoundException
  302. * @throws \think\exception\DbException
  303. */
  304. public function user_binding_phone(Request $request)
  305. {
  306. list($phone, $captcha, $step) = $request->postMore([
  307. ['phone', ''],
  308. ['captcha', ''],
  309. ['step', 0]
  310. ], true);
  311. //验证手机号
  312. try {
  313. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  314. } catch (ValidateException $e) {
  315. return app('json')->fail($e->getError());
  316. }
  317. if (!$step) {
  318. //验证验证码
  319. $verifyCode = CacheService::get('code_' . $phone);
  320. if (!$verifyCode)
  321. return app('json')->fail(410009);
  322. $verifyCode = substr($verifyCode, 0, 6);
  323. if ($verifyCode != $captcha)
  324. return app('json')->fail(410010);
  325. }
  326. $uid = (int)$request->uid();
  327. $re = $this->services->userBindindPhone($uid, $phone, $step);
  328. if ($re) {
  329. CacheService::delete('code_' . $phone);
  330. return app('json')->success($re['msg'] ?? 410016, $re['data'] ?? []);
  331. } else
  332. return app('json')->fail(410017);
  333. }
  334. public function update_binding_phone(Request $request)
  335. {
  336. [$phone, $captcha] = $request->postMore([
  337. ['phone', ''],
  338. ['captcha', ''],
  339. ], true);
  340. //验证手机号
  341. try {
  342. validate(RegisterValidates::class)->scene('code')->check(['phone' => $phone]);
  343. } catch (ValidateException $e) {
  344. return app('json')->fail($e->getError());
  345. }
  346. //验证验证码
  347. $verifyCode = CacheService::get('code_' . $phone);
  348. if (!$verifyCode)
  349. return app('json')->fail(410009);
  350. $verifyCode = substr($verifyCode, 0, 6);
  351. if ($verifyCode != $captcha)
  352. return app('json')->fail(410010);
  353. $uid = (int)$request->uid();
  354. $re = $this->services->updateBindindPhone($uid, $phone);
  355. if ($re) {
  356. CacheService::delete('code_' . $phone);
  357. return app('json')->success($re['msg'] ?? 100001, $re['data'] ?? []);
  358. } else
  359. return app('json')->fail(100007);
  360. }
  361. /**
  362. * 设置扫描二维码状态
  363. * @param string $code
  364. * @return mixed
  365. */
  366. public function setLoginKey(string $code)
  367. {
  368. if (!$code) {
  369. return app('json')->fail(410020);
  370. }
  371. $cacheCode = CacheService::get($code);
  372. if ($cacheCode === false || $cacheCode === null) {
  373. return app('json')->fail(410021);
  374. }
  375. CacheService::set($code, '0', 600);
  376. return app('json')->success();
  377. }
  378. /**
  379. * apple快捷登陆
  380. * @param Request $request
  381. * @param WechatServices $services
  382. * @return mixed
  383. * @throws \Psr\SimpleCache\InvalidArgumentException
  384. * @throws \think\db\exception\DataNotFoundException
  385. * @throws \think\db\exception\ModelNotFoundException
  386. */
  387. public function appleLogin(Request $request, WechatServices $services)
  388. {
  389. [$openId, $phone, $email, $captcha] = $request->postMore([
  390. ['openId', ''],
  391. ['phone', ''],
  392. ['email', ''],
  393. ['captcha', '']
  394. ], true);
  395. if ($phone) {
  396. if (!$captcha) {
  397. return app('json')->fail(410004);
  398. }
  399. //验证验证码
  400. $verifyCode = CacheService::get('code_' . $phone);
  401. if (!$verifyCode)
  402. return app('json')->fail(410009);
  403. $verifyCode = substr($verifyCode, 0, 6);
  404. if ($verifyCode != $captcha) {
  405. CacheService::delete('code_' . $phone);
  406. return app('json')->fail(410010);
  407. }
  408. }
  409. if ($email == '') $email = substr(md5($openId), 0, 12);
  410. $userInfo = [
  411. 'openId' => $openId,
  412. 'unionid' => '',
  413. 'avatarUrl' => sys_config('h5_avatar'),
  414. 'nickName' => $email,
  415. ];
  416. $token = $services->appAuth($userInfo, $phone, 'apple');
  417. if ($token) {
  418. return app('json')->success(410001, $token);
  419. } else if ($token === false) {
  420. return app('json')->success(410001, ['isbind' => true]);
  421. } else {
  422. return app('json')->fail(410019);
  423. }
  424. }
  425. }