AuthController.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <?php
  2. namespace App\Http\Controllers\Api\Base;
  3. use App\Http\Controllers\Controller;
  4. use App\Repositories\Enums\ResponseCodeEnum;
  5. use App\Services\Base\UserService;
  6. use App\Services\Base\AuthService;
  7. use App\Support\Traits\LoginLimit;
  8. use Carbon\Carbon;
  9. use EasyWeChat\Factory;
  10. use Illuminate\Http\Request;
  11. use Illuminate\Support\Arr;
  12. use Illuminate\Support\Facades\Cache;
  13. /**
  14. * 用户登录
  15. */
  16. class AuthController extends Controller
  17. {
  18. use LoginLimit;
  19. /**
  20. * @var AuthService
  21. */
  22. private $authService;
  23. /**
  24. * AdminService
  25. * @var
  26. */
  27. private $userService;
  28. /**
  29. * AuthController constructor.
  30. *
  31. * @param AuthService $authService
  32. */
  33. public function __construct(AuthService $authService, UserService $userService)
  34. {
  35. parent::__construct();
  36. $this->authService = $authService;
  37. $this->userService = $userService;
  38. }
  39. /**
  40. * 账号密码登录
  41. * @must
  42. * @param Request $request
  43. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  44. * @throws \Illuminate\Validation\ValidationException
  45. */
  46. public function accountLogin(Request $request)
  47. {
  48. $this->validate($request, [
  49. 'username' => 'required',
  50. 'password' => 'required|min:6'
  51. ], [], [
  52. 'username' => '账号',
  53. 'password' => '密码',
  54. ]);
  55. $credentials = $request->only(['username', 'password']);
  56. // if (is_mobile()) {
  57. // $this->validate($request, [
  58. // 'type' => 'required',
  59. // ], [], ['type' => '角色类型']);
  60. // $credentials['type'] = $request->get('type');
  61. // }
  62. $username = $request->get('username');
  63. $msg = $this->isCanLogin($request, $username, 'api');
  64. if ($msg) {
  65. return $this->response->fail($msg);
  66. }
  67. $token = $this->userService->handleAccountLogin($credentials, $request);
  68. $this->clearLoginLogs($request, $username, 'api');
  69. if ($token) {
  70. $this->clearLoginLogs($request, $username, 'api');
  71. $expires_in = auth()->factory()->getTTL() * 60;
  72. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  73. $token = 'Bearer ' . $token;
  74. return $this->response->success(compact('token', 'expires_in'));
  75. }
  76. $this->storeLoginLog($request, $username, 'api');
  77. return $this->response->fail('账号或者密码错误!');
  78. }
  79. /**
  80. * 微信小程序绑定登录
  81. * @must
  82. * @param Request $request
  83. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  84. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  85. * @throws \Illuminate\Validation\ValidationException
  86. * @throws \Prettus\Validator\Exceptions\ValidatorException
  87. */
  88. public function miniProgramLogin(Request $request)
  89. {
  90. $this->validate($request, [
  91. 'code' => 'required|string',
  92. 'appid' => 'required|string',
  93. 'phone_detail' => 'sometimes'
  94. ], [], [
  95. 'code' => 'Code',
  96. 'appid' => 'AppId',
  97. 'phone_detail' => '手机信息',
  98. ]);
  99. $auth = $this->authService->handleMiniProgramLogin($request);
  100. $token = $this->userService->handleAuthLogin($auth);
  101. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  102. $token = 'Bearer ' . $token;
  103. $expires_in = auth()->factory()->getTTL() * 60;
  104. return $this->response->success(compact('token', 'expires_in'));
  105. }
  106. /**
  107. * 绑定微信号
  108. * @param Request $request
  109. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  110. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  111. * @throws \Illuminate\Validation\ValidationException
  112. * @throws \Prettus\Validator\Exceptions\ValidatorException
  113. */
  114. public function bindWechat(Request $request)
  115. {
  116. $this->validate($request, [
  117. 'code' => 'required|string',
  118. 'appid' => 'required|string',
  119. 'type' => 'required|in:3,4,5',
  120. 'phone_detail' => 'sometimes'
  121. ], [], [
  122. 'code' => 'Code',
  123. 'appid' => 'AppId',
  124. 'phone_detail' => '手机信息',
  125. ]);
  126. $auth = $this->authService->handleMiniProgramLogin($request);
  127. $this->userService->handleBindWechat($auth);
  128. return $this->response->ok('绑定成功');
  129. }
  130. /**
  131. * 绑定微信号
  132. * @param Request $request
  133. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  134. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  135. * @throws \Illuminate\Validation\ValidationException
  136. * @throws \Prettus\Validator\Exceptions\ValidatorException
  137. */
  138. public function unbindWechat()
  139. {
  140. $this->userService->handleUnbindWechat();
  141. return $this->response->ok('绑定成功');
  142. }
  143. /**
  144. * 退出登录
  145. * @must
  146. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  147. */
  148. public function logout()
  149. {
  150. auth('api')->logout();
  151. return $this->response->ok('操作成功');
  152. }
  153. /**
  154. * 登录用户信息
  155. * @must
  156. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  157. */
  158. public function me()
  159. {
  160. $user = $this->userService->handleMe();
  161. return $this->response->success($user);
  162. }
  163. /**
  164. * 刷新token
  165. * @must
  166. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  167. */
  168. public function refreshToken()
  169. {
  170. $token = $this->authService->handleRefreshToken();
  171. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  172. $token = 'Bearer ' . $token;
  173. $expires_in = auth()->factory()->getTTL() * 60;
  174. return $this->response->success(compact('token', 'expires_in'));
  175. }
  176. /**
  177. * 微信小程序绑定用户手机号
  178. * @must
  179. * @param Request $request
  180. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\Resource|void
  181. * Author: Mead
  182. */
  183. public function miniBindMobile(Request $request)
  184. {
  185. $this->validate($request, [
  186. 'iv' => 'required|string',
  187. 'encryptedData' => 'required|string',
  188. ]);
  189. //微信解析手机号
  190. $user = login_user();
  191. $iv = $request->get('iv');
  192. $encryptedData = $request->get('encryptedData');
  193. $session = Cache::get("cache:service:auth:session_key:api:" . $user['wechat_auth_id']);
  194. if (!$session) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '请重新登录');
  195. $miniConfig = wechat_mini_config(0);
  196. $miniProgram = Factory::miniProgram($miniConfig);
  197. try {
  198. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  199. } catch (\Exception $exception) {
  200. exception($exception);
  201. }
  202. if (!array_key_exists('purePhoneNumber', $decryptedData)) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '解密数据不对');
  203. $mobile = $decryptedData['purePhoneNumber'];
  204. $this->userService->handleBindMobile($user['id'], $mobile);
  205. return $this->response->ok('绑定成功');
  206. }
  207. /**
  208. * 修改密码
  209. * @must
  210. * @param Request $request
  211. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  212. * @throws \Illuminate\Validation\ValidationException
  213. * @throws \Prettus\Validator\Exceptions\ValidatorException
  214. */
  215. public function updatePassword(Request $request)
  216. {
  217. $data = $this->validateData($request, [
  218. 'password' => 'required|confirmed|min:6'
  219. ], [
  220. 'password' => '密码',
  221. ]);
  222. $password = $data['password'];
  223. if (!check_password($password)) {
  224. return $this->response->fail('密码太简单', ResponseCodeEnum::SERVICE_OPERATION_ERROR);
  225. }
  226. $this->userService->handleMeResetPassword($password);
  227. return $this->response->ok('修改成功');
  228. }
  229. /**
  230. * 更新个人信息
  231. * @must
  232. * @param Request $request
  233. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  234. */
  235. public function updateInfo(Request $request)
  236. {
  237. $fields = $this->validateData($request, [
  238. 'fields' => 'required|array',
  239. ], [
  240. 'fields' => '字段表',
  241. ])['fields'];
  242. $da = [
  243. 'name' => [
  244. 'rule' => 'required|string',
  245. 'name' => '姓名',
  246. 'key' => 'name',
  247. ],
  248. 'sex' => [
  249. 'rule' => 'required|in:1,2',
  250. 'name' => '性别',
  251. 'key' => 'sex',
  252. ],
  253. 'headimg' => [
  254. 'rule' => 'required|string',
  255. 'name' => '头像',
  256. 'key' => 'headimg',
  257. ],
  258. 'email' => [
  259. 'rule' => 'required|mail',
  260. 'name' => '邮箱',
  261. 'key' => 'email',
  262. ],
  263. 'extra_fields.wechat_no' => [
  264. 'rule' => 'required|string',
  265. 'name' => '微信号',
  266. 'key' => 'extra_fields.wechat_no',
  267. ],
  268. ];
  269. $rules = Arr::only($da, $fields);
  270. $data = $this->validateData($request, Arr::pluck($rules, 'rule', 'key'), Arr::pluck($rules, 'name', 'key'));
  271. $this->userService->handleMeUpdate($data);
  272. return $this->response->ok('更新成功');
  273. }
  274. /**
  275. * 更新个人信息[微信]
  276. * @must
  277. * @param Request $request
  278. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  279. */
  280. public function miniUpdateInfo(Request $request)
  281. {
  282. $this->validate($request, [
  283. 'iv' => 'required',
  284. 'encryptedData' => 'required',
  285. ]);
  286. //微信解析手机号
  287. $user = login_user();
  288. $iv = $request->get('iv');
  289. $encryptedData = $request->get('encryptedData');
  290. $session = Cache::get("cache:service:auth:session_key:" . $user['wechat_auth_id']);
  291. if ($session) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '请重新登录');
  292. $miniConfig = wechat_mini_config(0);
  293. $miniProgram = Factory::miniProgram($miniConfig);
  294. try {
  295. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  296. } catch (\Exception $exception) {
  297. exception($exception);
  298. }
  299. return $this->response->ok('更新成功');
  300. }
  301. /**
  302. * 发送验证码
  303. * @param Request $request
  304. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  305. * @throws \Illuminate\Validation\ValidationException
  306. */
  307. public function sendLoginValidateCode(Request $request)
  308. {
  309. $this->validateData($request, [
  310. 'mobile' => 'required|mobile'
  311. ], ['mobile' => '手机号']);
  312. $mobile = $request->get('mobile');
  313. $day = date('Y-m-d');
  314. $nums = Cache::get("controller:Api:AuthController:sendLoginValidateCode:{$mobile}:{$day}", 0);
  315. if ($nums > 3) {
  316. return $this->response->fail('你今天请求的次数太多了,请明天再试。');
  317. }
  318. Cache::increment("controller:Api:AuthController:sendLoginValidateCode:{$mobile}:{$day}", 1);
  319. $code = rand(100000, 999999);
  320. try {
  321. // app('easy_sms')->send($mobile, [
  322. // 'template' => config('sms.template.verification_code'),
  323. // 'data' => [
  324. // 'number' => (string)$code
  325. // ]
  326. // ]);
  327. } catch (\Exception $exception) {
  328. exception($exception->getException(config('sms.default.gateways')[0]));
  329. }
  330. Cache::put('controller:sendLoginValidateCode:mobile:' . $mobile, $code, Carbon::now()->addMinutes(5));
  331. return $this->response->ok('发送成功' . $code);
  332. }
  333. /**
  334. * 手机号登录
  335. * @param Request $request
  336. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  337. * @throws \Illuminate\Validation\ValidationException
  338. * @throws \Prettus\Validator\Exceptions\ValidatorException
  339. */
  340. public function mobileLogin(Request $request)
  341. {
  342. $this->validateData($request, [
  343. 'mobile' => 'required|mobile',
  344. 'code' => 'required|size:6',
  345. ], ['mobile' => '手机号', 'code' => '验证码']);
  346. $mobile = $request->get('mobile');
  347. $code = $request->get('code');
  348. $yun_code = Cache::get('controller:sendLoginValidateCode:mobile:' . $mobile, false);
  349. // if ($yun_code !== $code) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '验证码不对');
  350. $token = $this->userService->handleMobileLogin($mobile);
  351. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  352. $token = 'Bearer ' . $token;
  353. $expires_in = auth()->factory()->getTTL() * 60;
  354. return $this->response->success(compact('token', 'expires_in'));
  355. }
  356. }