AuthController.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <?php
  2. namespace App\Http\Controllers\Admin\Base;
  3. use App\Http\Controllers\Controller;
  4. use App\Http\Middleware\SingleLoginLimit;
  5. use App\Repositories\Enums\Base\AdminTypeEnum;
  6. use App\Repositories\Enums\ModelStatusEnum;
  7. use App\Repositories\Enums\ResponseCodeEnum;
  8. use App\Repositories\Models\Base\Admin;
  9. use App\Services\Base\AdminService;
  10. use App\Services\Base\AuthService;
  11. use App\Support\Traits\LoginLimit;
  12. use Carbon\Carbon;
  13. use EasyWeChat\Factory;
  14. use Illuminate\Http\Request;
  15. use Illuminate\Support\Arr;
  16. use Illuminate\Support\Facades\Cache;
  17. /**
  18. * 用户登录
  19. */
  20. class AuthController extends Controller
  21. {
  22. use LoginLimit;
  23. /**
  24. * @var AuthService
  25. */
  26. private $authService;
  27. /**
  28. * AdminService
  29. * @var
  30. */
  31. private $adminService;
  32. /**
  33. * AuthController constructor.
  34. *
  35. * @param AuthService $authService
  36. */
  37. public function __construct(AuthService $authService, AdminService $adminService)
  38. {
  39. parent::__construct();
  40. $this->middleware('checkUserPermission', ['except' => ['accountLogin', 'miniProgramLogin', 'miniProgramMobileLogin', 'testMobile']]);
  41. $this->authService = $authService;
  42. $this->adminService = $adminService;
  43. }
  44. /**
  45. * 账号密码登录
  46. * @must
  47. * @param Request $request
  48. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  49. * @throws \Illuminate\Validation\ValidationException
  50. */
  51. public function accountLogin(Request $request)
  52. {
  53. $this->validate($request, [
  54. 'username' => 'required',
  55. 'password' => 'required|min:6'
  56. ], [], [
  57. 'username' => '账号',
  58. 'password' => '密码',
  59. ]);
  60. $credentials = $request->only(['username', 'password']);
  61. if (is_mobile()) {
  62. $credentials['type'] = AdminTypeEnum::STUDENT;
  63. }
  64. $username = $request->get('username');
  65. $msg = $this->isCanLogin($request, $username);
  66. if ($msg) {
  67. return $this->response->fail($msg);
  68. }
  69. $token = $this->adminService->handleAccountLogin($credentials, $request);
  70. if ($token) {
  71. $this->clearLoginLogs($request, $username);
  72. $expires_in = auth()->factory()->getTTL() * 60;
  73. $this->singleLoginSetToken(login_admin_id(), $token, 'admins');
  74. $token = 'Bearer ' . $token;
  75. $is_clear_log = true;
  76. return $this->response->success(compact('token', 'expires_in', 'is_clear_log'));
  77. }
  78. $this->storeLoginLog($request, $username);
  79. return $this->response->fail('账号或者密码错误!');
  80. }
  81. /**
  82. * 微信小程序绑定登录
  83. * @must
  84. * @param Request $request
  85. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  86. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  87. * @throws \Illuminate\Validation\ValidationException
  88. * @throws \Prettus\Validator\Exceptions\ValidatorException
  89. */
  90. public function miniProgramLogin(Request $request)
  91. {
  92. $this->validate($request, [
  93. 'code' => 'required|string',
  94. 'appid' => 'required|string',
  95. // 'type' => 'required|in:3,4,5',
  96. 'phone_detail' => 'sometimes'
  97. ], [], [
  98. 'code' => 'Code',
  99. 'appid' => 'AppId',
  100. 'phone_detail' => '手机信息',
  101. ]);
  102. $auth = $this->authService->handleIsMiniProgramLogin($request);
  103. if (!$auth) {
  104. return $this->response->success(['token' => false]);
  105. }
  106. $token = $this->adminService->handleAuthLogin($auth);
  107. $this->singleLoginSetToken(login_admin_id(), $token, 'admins');
  108. $token = 'Bearer ' . $token;
  109. $expires_in = auth()->factory()->getTTL() * 60;
  110. return $this->response->success(compact('token', 'expires_in'));
  111. }
  112. /*
  113. * 手机号+小程序登录
  114. */
  115. public function miniProgramMobileLogin(Request $request)
  116. {
  117. $this->validateData($request, [
  118. 'code' => 'required|string',
  119. 'appid' => 'required|string',
  120. // 'type' => 'required',
  121. 'iv' => 'required',
  122. 'encryptedData' => 'required',
  123. ], [
  124. 'code' => 'Code',
  125. 'appid' => 'AppId',
  126. 'iv' => 'iv',
  127. 'encryptedData' => 'encryptedData',
  128. 'type' => '用户类型',
  129. ]);
  130. $iv = $request->get('iv');
  131. $encryptedData = $request->get('encryptedData');
  132. $type = 0;
  133. $auth = $this->authService->handleMiniProgramLogin($request);
  134. $session = Cache::get("cache:service:auth:session_key:api:" . $auth['id']);
  135. if (!$session) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '请重新登录');
  136. $miniConfig = wechat_mini_config($type);
  137. $miniProgram = Factory::miniProgram($miniConfig);
  138. try {
  139. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  140. } catch (\Exception $exception) {
  141. exception($exception);
  142. }
  143. $mobile = $decryptedData['purePhoneNumber'];
  144. $token = $this->adminService->handleAuthMobileLogin($auth, $mobile);
  145. $this->singleLoginSetToken(login_admin_id(), $token, 'admins');
  146. $token = 'Bearer ' . $token;
  147. $expires_in = auth()->factory()->getTTL() * 60;
  148. return $this->response->success(compact('token', 'expires_in'));
  149. }
  150. /**
  151. * 绑定微信号
  152. * @param Request $request
  153. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  154. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  155. * @throws \Illuminate\Validation\ValidationException
  156. * @throws \Prettus\Validator\Exceptions\ValidatorException
  157. */
  158. public function bindWechat(Request $request)
  159. {
  160. $this->validate($request, [
  161. 'code' => 'required|string',
  162. 'appid' => 'required|string',
  163. 'type' => 'required|in:3,4,5',
  164. 'phone_detail' => 'sometimes'
  165. ], [], [
  166. 'code' => 'Code',
  167. 'appid' => 'AppId',
  168. 'phone_detail' => '手机信息',
  169. ]);
  170. $auth = $this->authService->handleMiniProgramLogin($request);
  171. $this->adminService->handleBindWechat($auth);
  172. return $this->response->ok('绑定成功');
  173. }
  174. /**
  175. * 绑定微信号
  176. * @param Request $request
  177. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  178. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  179. * @throws \Illuminate\Validation\ValidationException
  180. * @throws \Prettus\Validator\Exceptions\ValidatorException
  181. */
  182. public function unbindWechat()
  183. {
  184. $this->adminService->handleUnbindWechat();
  185. return $this->response->ok('绑定成功');
  186. }
  187. /**
  188. * 退出登录
  189. * @must
  190. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  191. */
  192. public function logout()
  193. {
  194. auth('admins')->logout();
  195. return $this->response->ok('操作成功');
  196. }
  197. /**
  198. * 登录用户信息
  199. * @must
  200. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  201. */
  202. public function me()
  203. {
  204. return $this->response->success($this->adminService->handleMe());
  205. }
  206. /**
  207. * 刷新token
  208. * @must
  209. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  210. */
  211. public function refreshToken()
  212. {
  213. $token = $this->authService->handleRefreshToken();
  214. $this->singleLoginSetToken(login_admin_id(), $token, 'admins');
  215. $token = 'Bearer ' . $token;
  216. $expires_in = auth()->factory()->getTTL() * 60;
  217. return $this->response->success(compact('token', 'expires_in'));
  218. }
  219. /**
  220. * 锁屏验证密码
  221. * @must
  222. * @param Request $request
  223. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  224. * @throws \Illuminate\Validation\ValidationException
  225. */
  226. public function validatePassword(Request $request)
  227. {
  228. $this->validate($request, [
  229. 'id' => 'required',
  230. 'password' => 'required'
  231. ]);
  232. $username = $request->get('id');
  233. $msg = $this->isCanLogin($request, $username);
  234. if ($msg) {
  235. return $this->response->fail($msg);
  236. }
  237. $status = $this->adminService->handleConfirmPassword($request);
  238. if ($status) {
  239. $this->clearLoginLogs($request, $username);
  240. } else {
  241. $this->storeLoginLog($request, $username);
  242. }
  243. return $this->response->success(compact('status'));
  244. }
  245. /**
  246. * 微信小程序绑定用户手机号
  247. * @must
  248. * @param Request $request
  249. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\Resource|void
  250. * Author: Mead
  251. */
  252. public function miniBindMobile(Request $request)
  253. {
  254. $this->validate($request, [
  255. 'iv' => 'required',
  256. 'encryptedData' => 'required',
  257. ]);
  258. //微信解析手机号
  259. $admin = login_admin();
  260. $iv = $request->get('iv');
  261. $encryptedData = $request->get('encryptedData');
  262. $type = $request->get('type');
  263. $session = Cache::get("cache:service:auth:session_key:admins:" . $admin['wechat_auth_id']);
  264. if (!$session) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '请重新登录');
  265. $miniConfig = wechat_mini_config($type);
  266. $miniProgram = Factory::miniProgram($miniConfig);
  267. try {
  268. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  269. } catch (\Exception $exception) {
  270. exception($exception);
  271. }
  272. $mobile = $decryptedData['purePhoneNumber'];
  273. $this->adminService->handleBindMobile($admin['id'], $mobile);
  274. return $this->response->ok('绑定成功');
  275. }
  276. /**
  277. * 修改密码
  278. * @must
  279. * @param Request $request
  280. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  281. * @throws \Illuminate\Validation\ValidationException
  282. * @throws \Prettus\Validator\Exceptions\ValidatorException
  283. */
  284. public function updatePassword(Request $request)
  285. {
  286. $data = $this->validateData($request, [
  287. 'password' => 'required|confirmed|min:6'
  288. ], [
  289. 'password' => '密码',
  290. ]);
  291. $password = $data['password'];
  292. if (!check_password($password)) {
  293. return $this->response->fail('密码太简单', ResponseCodeEnum::SERVICE_OPERATION_ERROR);
  294. }
  295. $this->adminService->handleMeResetPassword($password);
  296. return $this->response->ok('修改成功');
  297. }
  298. /**
  299. * 更新个人信息
  300. * @must
  301. * @param Request $request
  302. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  303. */
  304. public function updateInfo(Request $request)
  305. {
  306. $admin = login_admin();
  307. $fields = $this->validateData($request, [
  308. 'fields' => 'required|array',
  309. ], [
  310. 'fields' => '字段表',
  311. ])['fields'];
  312. $da = [
  313. 'name' => [
  314. 'rule' => 'required|string',
  315. 'name' => '姓名',
  316. 'key' => 'name',
  317. ],
  318. 'sex' => [
  319. 'rule' => 'required|in:1,2',
  320. 'name' => '性别',
  321. 'key' => 'sex',
  322. ],
  323. 'email' => [
  324. 'rule' => 'required|mail',
  325. 'name' => '邮箱',
  326. 'key' => 'email',
  327. ],
  328. 'department_id' => [
  329. 'rule' => 'required',
  330. 'name' => '部门 id',
  331. 'key' => 'department_id',
  332. ],
  333. 'user_no' => [
  334. 'rule' => 'required',
  335. 'name' => '学号',
  336. 'key' => 'user_no',
  337. ],
  338. 'grade' => [
  339. 'rule' => 'required',
  340. 'name' => '年级',
  341. 'key' => 'grade',
  342. ],
  343. 'class_name' => [
  344. 'rule' => 'required',
  345. 'name' => '班级',
  346. 'key' => 'class_name',
  347. ],
  348. 'type' => [
  349. 'rule' => 'required',
  350. 'name' => '类型',
  351. 'key' => 'type',
  352. ],
  353. 'extra_fields' => [
  354. 'rule' => 'required',
  355. 'name' => '签章',
  356. 'key' => 'extra_fields',
  357. ]
  358. ];
  359. $rules = Arr::only($da, $fields);
  360. $data = $this->validateData($request, Arr::pluck($rules, 'rule', 'key'), Arr::pluck($rules, 'name', 'key'));
  361. // $data['user_no'] = strtoupper($data['user_no']);
  362. //
  363. // if (User::query()->where('user_no', $data['user_no'])->where('id', '<>', $admin['id'])->exists()) {
  364. // return $this->response->fail('该学号已经实名,请勿重复操作');
  365. // }
  366. $this->adminService->handleMeUpdate($data);
  367. return $this->response->ok('更新成功');
  368. }
  369. /**
  370. * 更新个人信息[微信]
  371. * @must
  372. * @param Request $request
  373. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  374. */
  375. public function miniUpdateInfo(Request $request)
  376. {
  377. $admin = login_admin();
  378. return $this->response->ok('更新成功');
  379. }
  380. /**
  381. * 发送验证码
  382. * @param Request $request
  383. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  384. * @throws \Illuminate\Validation\ValidationException
  385. */
  386. public function sendValidateCode(Request $request)
  387. {
  388. $this->validateData($request, [
  389. 'mobile' => 'required|mobile'
  390. ], ['mobile' => '手机号']);
  391. $mobile = $request->get('mobile');
  392. $day = date('Y-m-d');
  393. $nums = Cache::get("controller:Admin:AuthController:sendLoginValidateCode:{$mobile}:{$day}", 0);
  394. if ($nums > 3) {
  395. return $this->response->fail('你今天请求的次数太多了,请明天再试。');
  396. }
  397. Cache::increment("controller:Admin:AuthController:sendLoginValidateCode:{$mobile}:{$day}", 1);
  398. $code = rand(100000, 999999);
  399. try {
  400. app('easy_sms')->send($mobile, [
  401. 'template' => config('sms.template.verification_code'),
  402. 'data' => [
  403. 'number' => (string)$code
  404. ]
  405. ]);
  406. } catch (\Exception $exception) {
  407. exception($exception->getException(config('sms.default.gateways')[0]));
  408. }
  409. Cache::put('controller:admin:sendValidateCode:mobile:' . $mobile, $code, Carbon::now()->addMinutes(5));
  410. return $this->response->ok('发送成功');
  411. }
  412. /**
  413. * 换绑手机号
  414. * @param Request $request
  415. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  416. * @throws \Illuminate\Validation\ValidationException
  417. */
  418. public function updateMobile(Request $request)
  419. {
  420. $this->validateData($request, [
  421. 'mobile' => 'required|mobile',
  422. 'code' => 'required|size:6',
  423. ], ['mobile' => '手机号', 'code' => '验证码']);
  424. $mobile = $request->get('mobile');
  425. $code = $request->get('code');
  426. $yun_code = Cache::get('controller:sendLoginValidateCode:mobile:' . $mobile, false);
  427. if ($yun_code !== $code) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '验证码不对');
  428. $this->adminService->handleBindMobile(login_admin_id(), $mobile);
  429. return $this->response->ok('换绑成功');
  430. }
  431. public function testMobile(Request $request)
  432. {
  433. $this->validate($request, [
  434. 'mobile' => 'required|mobile',
  435. ], [], [
  436. 'mobile' => '手机号',
  437. ]);
  438. $mobile = $request->get('mobile');
  439. // $admin = User::query()->where('mobile', $mobile)->first();
  440. $admin = Admin::query()->firstOrCreate(['mobile' => $mobile], ['status' => ModelStatusEnum::OK, 'username' => $mobile, 'name' => $mobile]);
  441. if (!$admin) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '找不该用户');
  442. $token = auth('admins')->login($admin);
  443. //单机登录限制
  444. $admin_id = $admin['id'];
  445. SingleLoginLimit::setToken('admins', $admin_id, $token);
  446. $expires_in = auth()->factory()->getTTL() * 60;
  447. $this->singleLoginSetToken(login_admin_id(), $token, 'admins');
  448. $token = 'Bearer ' . $token;
  449. return $this->response->success(compact('token', 'expires_in'));
  450. }
  451. }