Auth.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. namespace app\controller\api;
  3. use app\common\repositories\user\UserRepository;
  4. use app\common\repositories\wechat\RoutineQrcodeRepository;
  5. use app\common\repositories\wechat\WechatUserRepository;
  6. use app\validate\api\ChangePasswordValidate;
  7. use app\validate\api\UserAuthValidate;
  8. use ln\basic\BaseController;
  9. use ln\services\MiniProgramService;
  10. use ln\services\WechatService;
  11. use ln\services\YunxinSmsService;
  12. use Exception;
  13. use Gregwar\Captcha\CaptchaBuilder;
  14. use Gregwar\Captcha\PhraseBuilder;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use think\db\exception\DataNotFoundException;
  17. use think\db\exception\DbException;
  18. use think\db\exception\ModelNotFoundException;
  19. use think\exception\ValidateException;
  20. use think\facade\Cache;
  21. /**
  22. * Class Auth
  23. * @package app\controller\api
  24. * @author zfy
  25. * @day 2020-05-06
  26. */
  27. class Auth extends BaseController
  28. {
  29. public function test(){
  30. }
  31. /**
  32. * @param UserRepository $repository
  33. * @return mixed
  34. * @throws DbException
  35. * @author zfy
  36. * @day 2020/6/1
  37. */
  38. public function login(UserRepository $repository)
  39. {
  40. $account = $this->request->param('account');
  41. if(Cache::get('api_login_freeze_'.$account))
  42. return app('json')->fail('账号或密码错误次数太多,请稍后在尝试');
  43. if (!$account)
  44. return app('json')->fail('请输入账号');
  45. $user = $repository->accountByUser($this->request->param('account'));
  46. if (!$user) $this->loginFailure($account);
  47. if (!password_verify($pwd = (string)$this->request->param('password'), $user['pwd'])) $this->loginFailure($account);
  48. $user = $repository->mainUser($user);
  49. $pid = $this->request->param('spread', 0);
  50. $repository->bindSpread($user, intval($pid));
  51. $tokenInfo = $repository->createToken($user);
  52. $repository->loginAfter($user);
  53. return app('json')->success($repository->returnToken($user, $tokenInfo));
  54. }
  55. /**
  56. * TODO 登录尝试次数限制
  57. * @param $account
  58. * @param int $number
  59. * @param int $n
  60. * @author Qinii
  61. * @day 7/6/21
  62. */
  63. public function loginFailure($account,$number = 5,$n = 3)
  64. {
  65. $key = 'api_login_failuree_'.$account;
  66. $numb = Cache::get($key) ?? 0;
  67. $numb++;
  68. if($numb >= $number){
  69. $fail_key = 'api_login_freeze_'.$account;
  70. Cache::set($fail_key,1,15*60);
  71. throw new ValidateException('账号或密码错误次数太多,请稍后在尝试');
  72. }else{
  73. Cache::set($key,$numb,5*60);
  74. $msg = '账号或密码错误';
  75. $_n = $number - $numb;
  76. if($_n <= $n){
  77. $msg .= ',还可尝试'.$_n.'次';
  78. }
  79. throw new ValidateException($msg);
  80. }
  81. }
  82. /**
  83. * @return mixed
  84. * @author zfy
  85. * @day 2020/6/1
  86. */
  87. public function userInfo()
  88. {
  89. $user = $this->request->userInfo()->hidden(['label_id', 'group_id', 'pwd', 'addres', 'card_id', 'last_time', 'last_ip', 'create_time', 'mark', 'status', 'spread_uid', 'spread_time', 'real_name', 'birthday', 'brokerage_price']);
  90. $user->append(['service', 'total_collect_product', 'total_collect_store', 'total_coupon', 'total_visit_product', 'total_unread', 'total_recharge', 'lock_integral', 'total_integral']);
  91. $data = $user->toArray();
  92. $data['total_consume'] = $user['pay_price'];
  93. $data['extension_status'] = systemConfig('extension_status');
  94. return app('json')->success($data);
  95. }
  96. /**
  97. * @param UserRepository $repository
  98. * @return mixed
  99. * @author zfy
  100. * @day 2020/6/1
  101. */
  102. public function logout(UserRepository $repository)
  103. {
  104. $repository->clearToken($this->request->token());
  105. return app('json')->success('退出登录');
  106. }
  107. /**
  108. * @return mixed
  109. * @throws DataNotFoundException
  110. * @throws DbException
  111. * @throws ModelNotFoundException
  112. * @author zfy
  113. * @day 2020-05-11
  114. */
  115. public function auth()
  116. {
  117. $request = $this->request;
  118. $oauth = WechatService::create()->getApplication()->oauth;
  119. $oauth->setRequest(new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent()));
  120. try {
  121. $wechatInfo = $oauth->user()->getOriginal();
  122. } catch (Exception $e) {
  123. return app('json')->fail('授权失败[001]', ['message' => $e->getMessage()]);
  124. }
  125. if (!isset($wechatInfo['nickname'])) {
  126. return app('json')->fail('授权失败[002]');
  127. }
  128. /** @var WechatUserRepository $make */
  129. $make = app()->make(WechatUserRepository::class);
  130. $user = $make->syncUser($wechatInfo['openid'], $wechatInfo);
  131. if (!$user)
  132. return app('json')->fail('授权失败[003]');
  133. /** @var UserRepository $make */
  134. $userRepository = app()->make(UserRepository::class);
  135. $user[1] = $userRepository->mainUser($user[1]);
  136. $pid = $this->request->param('spread', 0);
  137. $userRepository->bindSpread($user[1], intval($pid));
  138. $tokenInfo = $userRepository->createToken($user[1]);
  139. $userRepository->loginAfter($user[1]);
  140. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  141. }
  142. /**
  143. * @return mixed
  144. * @throws DataNotFoundException
  145. * @throws DbException
  146. * @throws ModelNotFoundException
  147. * @author zfy
  148. * @day 2020-05-11
  149. */
  150. public function mpAuth()
  151. {
  152. list($code, $post_cache_key) = $this->request->params([
  153. 'code',
  154. 'cache_key',
  155. ], true);
  156. $session_key = Cache::get('eb_api_code_' . $post_cache_key);
  157. if (!$code && !$session_key)
  158. return app('json')->fail('授权失败,参数有误');
  159. $miniProgramService = MiniProgramService::create();
  160. if ($code && !$session_key) {
  161. try {
  162. $userInfoCong = $miniProgramService->getUserInfo($code);
  163. $session_key = $userInfoCong['session_key'];
  164. $cache_key = md5(time() . $code);
  165. Cache::set('eb_api_code_' . $cache_key, $session_key, 86400);
  166. } catch (Exception $e) {
  167. return app('json')->fail('获取session_key失败,请检查您的配置!', ['line' => $e->getLine(), 'message' => $e->getMessage()]);
  168. }
  169. }
  170. $data = $this->request->params([
  171. ['spread_spid', 0],
  172. ['spread_code', ''],
  173. ['iv', ''],
  174. ['encryptedData', ''],
  175. ]);
  176. try {
  177. //解密获取用户信息
  178. $userInfo = $miniProgramService->encryptor($session_key, $data['iv'], $data['encryptedData']);
  179. } catch (Exception $e) {
  180. if ($e->getCode() == '-41003') return app('json')->fail('获取会话密匙失败');
  181. throw $e;
  182. }
  183. if (!$userInfo) return app('json')->fail('openid获取失败');
  184. if (!isset($userInfo['openId'])) $userInfo['openId'] = $userInfoCong['openid'] ?? '';
  185. $userInfo['unionId'] = $userInfoCong['unionid'] ?? $userInfo['unionId'] ?? '';
  186. if (!$userInfo['openId']) return app('json')->fail('openid获取失败');
  187. /** @var WechatUserRepository $make */
  188. $make = app()->make(WechatUserRepository::class);
  189. $user = $make->syncRoutineUser($userInfo['openId'], $userInfo);
  190. if (!$user)
  191. return app('json')->fail('授权失败');
  192. /** @var UserRepository $make */
  193. $userRepository = app()->make(UserRepository::class);
  194. $user[1] = $userRepository->mainUser($user[1]);
  195. $code = intval($data['spread_code']['id'] ?? $data['spread_code']);
  196. //获取是否有扫码进小程序
  197. if ($code && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($code))) {
  198. $data['spread_spid'] = $info['third_id'];
  199. }
  200. $userRepository->bindSpread($user[1], intval($data['spread_spid']));
  201. $tokenInfo = $userRepository->createToken($user[1]);
  202. $userRepository->loginAfter($user[1]);
  203. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  204. }
  205. public function getCaptcha()
  206. {
  207. $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4));
  208. $key = uniqid(microtime(true), true);
  209. Cache::set('api_captche' . $key, $codeBuilder->getPhrase(), 300);
  210. $captcha = $codeBuilder->build()->inline();
  211. return app('json')->success(compact('key', 'captcha'));
  212. }
  213. protected function checkCaptcha($uni, string $code): bool
  214. {
  215. $cacheName = 'api_captche' . $uni;
  216. if (!Cache::has($cacheName)) return false;
  217. $key = Cache::get($cacheName);
  218. $res = strtolower($key) == strtolower($code);
  219. if ($res) Cache::delete($cacheName);
  220. return $res;
  221. }
  222. public function verify(UserAuthValidate $validate)
  223. {
  224. $data = $this->request->params(['phone', 'code', 'key', ['type', 'login']]);
  225. $validate->sceneVerify()->check($data);
  226. $sms_num_key = 'api.auth.num.' . $data['phone'];
  227. $num = Cache::get($sms_num_key) ? Cache::get($sms_num_key) : 0;
  228. if ($num > 2) {
  229. if (!$data['code'])
  230. return app('json')->make(402, '请输入验证码');
  231. if (!$this->checkCaptcha($data['key'], $data['code']))
  232. return app('json')->fail('验证码输入有误');
  233. }
  234. $sms = (YunxinSmsService::create());
  235. // if(!env('APP_DEBUG', false)){
  236. try {
  237. $sms_code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);
  238. $sms_time = systemConfig('sms_time') ? systemConfig('sms_time') : 30;
  239. $sms->send($data['phone'], 'VERIFICATION_CODE', ['code' => $sms_code, 'time' => $sms_time]);
  240. } catch (Exception $e) {
  241. return app('json')->fail($e->getMessage());
  242. }
  243. // }else{
  244. // $sms_code = 1234;
  245. // $sms_time = 5;
  246. // }
  247. $sms_key = $sms->sendSmsKey($data['phone'], $data['type']);
  248. Cache::set($sms_key, $sms_code, $sms_time * 60);
  249. Cache::set($sms_num_key, $num + 1, 300);
  250. //'短信发送成功'
  251. return app('json')->success('短信发送成功');
  252. }
  253. public function smsLogin(UserAuthValidate $validate, UserRepository $repository)
  254. {
  255. $data = $this->request->params(['phone', 'sms_code', 'spread']);
  256. $validate->sceneSmslogin()->check($data);
  257. if (!(YunxinSmsService::create())->checkSmsCode($data['phone'], $data['sms_code'], 'login'))
  258. return app('json')->fail('验证码不正确');
  259. $user = $repository->accountByUser($data['phone']);
  260. if (!$user) $user = $repository->registr($data['phone'], null);
  261. $user = $repository->mainUser($user);
  262. $repository->bindSpread($user, intval($data['spread']));
  263. $tokenInfo = $repository->createToken($user);
  264. $repository->loginAfter($user);
  265. return app('json')->success($repository->returnToken($user, $tokenInfo));
  266. }
  267. public function changePassword(ChangePasswordValidate $validate, UserRepository $repository)
  268. {
  269. $data = $this->request->params(['phone', 'sms_code', 'pwd']);
  270. $validate->check($data);
  271. $user = $repository->accountByUser($data['phone']);
  272. if (!$user) return app('json')->fail('用户不存在');
  273. if (!(YunxinSmsService::create())->checkSmsCode($data['phone'], $data['sms_code'], 'change_pwd'))
  274. return app('json')->fail('验证码不正确');
  275. $user->pwd = $repository->encodePassword($data['pwd']);
  276. $user->save();
  277. return app('json')->success('修改成功');
  278. }
  279. public function spread(UserRepository $userRepository)
  280. {
  281. $data = $this->request->params([
  282. ['spread_spid', 0],
  283. ['spread_code', null],
  284. ]);
  285. if (isset($data['spread_code']['id']) && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($data['spread_code']['id']))) {
  286. $data['spread_spid'] = $info['third_id'];
  287. }
  288. $userRepository->bindSpread($this->request->userInfo(), intval($data['spread_spid']));
  289. return app('json')->success();
  290. }
  291. /**
  292. * TODO 注册账号
  293. * @param UserAuthValidate $validate
  294. * @param UserRepository $repository
  295. * @return \think\response\Json
  296. * @author Qinii
  297. * @day 5/27/21
  298. */
  299. public function register(UserAuthValidate $validate, UserRepository $repository)
  300. {
  301. $data = $this->request->params(['phone', 'sms_code', 'spread','pwd']);
  302. $validate->check($data);
  303. if (!(YunxinSmsService::create())->checkSmsCode($data['phone'], $data['sms_code'], 'login'))
  304. return app('json')->fail('验证码不正确');
  305. $user = $repository->accountByUser($data['phone']);
  306. if ($user) return app('json')->fail('用户已存在');
  307. $user = $repository->registr($data['phone'], $data['pwd']);
  308. $user = $repository->mainUser($user);
  309. $repository->bindSpread($user, intval($data['spread']));
  310. $tokenInfo = $repository->createToken($user);
  311. $repository->loginAfter($user);
  312. return app('json')->success($repository->returnToken($user, $tokenInfo));
  313. }
  314. /**
  315. * App微信登陆
  316. * @param Request $request
  317. * @return mixed
  318. */
  319. public function appAuth()
  320. {
  321. $data = $this->request->params(['userInfo']);
  322. $user = app()->make(WechatUserRepository::class)->syncAppUser($data['userInfo']['unionId'], $data['userInfo']);
  323. if (!$user)
  324. return app('json')->fail('授权失败');
  325. /** @var UserRepository $make */
  326. $userRepository = app()->make(UserRepository::class);
  327. $user[1] = $userRepository->mainUser($user[1]);
  328. $tokenInfo = $userRepository->createToken($user[1]);
  329. $userRepository->loginAfter($user[1]);
  330. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  331. }
  332. public function getMerCertificate($merId)
  333. {
  334. $merId = (int)$merId;
  335. $data = $this->request->params(['key', 'code']);
  336. if (!$this->checkCaptcha($data['key'], $data['code']))
  337. return app('json')->fail('验证码输入有误');
  338. $certificate = merchantConfig($merId, 'mer_certificate') ?: [];
  339. if (!count($certificate))
  340. return app('json')->fail('该商户未上传证书');
  341. return app('json')->success($certificate);
  342. }
  343. public function appleAuth()
  344. {
  345. $data = $this->request->params(['openId', 'nickname']);
  346. $user = app()->make(WechatUserRepository::class)->syncAppUser($data['openId'], [
  347. 'nickName' => (string)$data['nickname'] ?: '用户' . strtoupper(substr(md5(time()), 0, 12))
  348. ], 'apple');
  349. if (!$user)
  350. return app('json')->fail('授权失败');
  351. /** @var UserRepository $make */
  352. $userRepository = app()->make(UserRepository::class);
  353. $user[1] = $userRepository->mainUser($user[1]);
  354. $tokenInfo = $userRepository->createToken($user[1]);
  355. $userRepository->loginAfter($user[1]);
  356. return app('json')->success($userRepository->returnToken($user[1], $tokenInfo));
  357. }
  358. }