AuthController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <?php
  2. namespace App\Http\Controllers\Api\Base;
  3. use App\Http\Controllers\Controller;
  4. use App\Repositories\Enums\ModelStatusEnum;
  5. use App\Repositories\Enums\ResponseCodeEnum;
  6. use App\Repositories\Models\Base\User;
  7. use App\Services\Base\UserService;
  8. use App\Services\Base\AuthService;
  9. use App\Support\Traits\LoginLimit;
  10. use Carbon\Carbon;
  11. use EasyWeChat\Factory;
  12. use Illuminate\Http\Request;
  13. use Illuminate\Support\Facades\Cache;
  14. use Overtrue\EasySms\PhoneNumber;
  15. /**
  16. * 用户登录
  17. */
  18. class AuthController extends Controller
  19. {
  20. use LoginLimit;
  21. /**
  22. * @var AuthService
  23. */
  24. private $authService;
  25. /**
  26. * UserService
  27. * @var
  28. */
  29. private $userService;
  30. /**
  31. * AuthController constructor.
  32. *
  33. * @param AuthService $authService
  34. */
  35. public function __construct(AuthService $authService, UserService $userService)
  36. {
  37. parent::__construct();
  38. $this->authService = $authService;
  39. $this->userService = $userService;
  40. }
  41. /**
  42. * 微信小程序绑定登录
  43. * @must
  44. * @param Request $request
  45. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  46. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  47. * @throws \Illuminate\Validation\ValidationException
  48. * @throws \Prettus\Validator\Exceptions\ValidatorException
  49. */
  50. public function wxLogin(Request $request)
  51. {
  52. $this->validateData($request, [
  53. 'code' => 'required|string',
  54. ], [
  55. 'code' => 'Code',
  56. ]);
  57. $code = $request->get('code');
  58. try {
  59. $app = Factory::officialAccount(config('wechat.official_account.default'));
  60. $user = $app->oauth->userFromCode($code);
  61. } catch (\Exception $exception) {
  62. $this->exception($exception);
  63. }
  64. $openId = $user->getId();
  65. $auth = $this->authService->handleCodeToAuth(config('wechat.official_account.default.app_id'), $openId);
  66. $session_key = $user->getAccessToken();
  67. if ($session_key) {
  68. Cache::put("cache:service:auth:session_key:api:" . $auth['id'], $session_key, Carbon::now()->addDay());
  69. Cache::put("cache:service:auth:userinfo:api:" . $auth['id'], [
  70. 'name' => $user->getName(),
  71. 'nickname' => $user->getNickname(),
  72. 'headimg' => $user->getAvatar(),
  73. 'data' => $user->getRaw()
  74. ], Carbon::now()->addDay());
  75. }
  76. if (!$auth['user_id']) {
  77. return $this->response->success([
  78. 'is_binding' => 0,
  79. 'auth_id' => $auth['id'],
  80. 'token' => null
  81. ]);
  82. }
  83. list($token, $user) = $this->userService->handleAuthLogin($auth);
  84. if (!$user) {
  85. return $this->response->success([
  86. 'is_binding' => 0,
  87. 'auth_id' => $auth['id'],
  88. 'token' => null
  89. ]);
  90. }
  91. if ($user->status == ModelStatusEnum::PAUSE) {
  92. return $this->response->success([
  93. 'is_binding' => 0,
  94. 'auth_id' => $auth['id'],
  95. 'token' => null
  96. ]);
  97. }
  98. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  99. $token = 'Bearer ' . $token;
  100. $expires_in = auth()->factory()->getTTL() * 60;
  101. $is_binding = 1;
  102. return $this->response->success(compact('is_binding', 'token', 'expires_in'));
  103. }
  104. /**
  105. * 退出登录
  106. * @must
  107. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  108. */
  109. public function logout()
  110. {
  111. //解绑微信号
  112. $this->userService->handleUnbindWechat();
  113. auth('api')->logout();
  114. return $this->response->ok('操作成功');
  115. }
  116. /**
  117. * 登录用户信息
  118. * @must
  119. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  120. */
  121. public function me()
  122. {
  123. $user = $this->userService->handleMe();
  124. return $this->response->success($user);
  125. }
  126. /**
  127. * 刷新token
  128. * @must
  129. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  130. */
  131. public function refreshToken()
  132. {
  133. $token = $this->authService->handleRefreshToken();
  134. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  135. $token = 'Bearer ' . $token;
  136. $expires_in = auth()->factory()->getTTL() * 60;
  137. return $this->response->success(compact('token', 'expires_in'));
  138. }
  139. /**
  140. * 发送验证码
  141. * @param Request $request
  142. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  143. * @throws \Illuminate\Validation\ValidationException
  144. */
  145. public function sendLoginValidateCode(Request $request)
  146. {
  147. $this->validateData($request, [
  148. 'mobile' => 'required',
  149. 'area_code' => 'required|string',
  150. ], ['mobile' => '手机号', 'area_code' => '国际码']);
  151. $mobile = $request->get('mobile');
  152. $area_code = $request->get('area_code', '+86');
  153. switch ($area_code) {
  154. case "+886":
  155. //中国台湾
  156. $this->validateData($request, [
  157. 'mobile' => 'required|mobile_TW',
  158. ], ['mobile' => '手机号']);
  159. break;
  160. case "+853":
  161. //中国澳门
  162. $this->validateData($request, [
  163. 'mobile' => 'required|mobile_OM',
  164. ], ['mobile' => '手机号']);
  165. break;
  166. case "+852":
  167. //中国香港
  168. $this->validateData($request, [
  169. 'mobile' => 'required|mobile_XG',
  170. ], ['mobile' => '手机号']);
  171. break;
  172. case '+86':
  173. default:
  174. //大陆
  175. $this->validateData($request, [
  176. 'mobile' => 'required|mobile',
  177. ], ['mobile' => '手机号']);
  178. $area_code = "+86";
  179. break;
  180. }
  181. $if = $this->userService->handleCheckMobileIsExists($mobile, $area_code);
  182. if (!$if) {
  183. abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '找不到该用户');
  184. }
  185. $code = rand(1000, 9999);
  186. $time = 10;
  187. $number = new PhoneNumber($mobile, $area_code);
  188. try {
  189. app('easy_sms')->send($number, [
  190. 'template' => ($area_code == '+86') ? config('sms.template.verification_code') : config('sms.template.verification_code_gj'),
  191. 'data' => [
  192. 'number' => (string)$code,
  193. 'time' => $time,
  194. ]
  195. ]);
  196. } catch (\Exception $exception) {
  197. exception($exception->getException(config('sms.default.gateways')[0]));
  198. }
  199. $key = "controller:sendLoginValidateCode:mobile:{$area_code}:{$mobile}";
  200. Cache::put($key, $code, Carbon::now()->addMinutes($time));
  201. return $this->response->success(['status' => 1], '发送成功');
  202. }
  203. /**
  204. * 手机号登录
  205. * @param Request $request
  206. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  207. * @throws \Illuminate\Validation\ValidationException
  208. * @throws \Prettus\Validator\Exceptions\ValidatorException
  209. */
  210. public function mobileLogin(Request $request)
  211. {
  212. $this->validateData($request, [
  213. 'auth_id' => 'required|integer',
  214. 'mobile' => 'required',
  215. 'area_code' => 'required|string',
  216. 'code' => 'required|size:4',
  217. ], [
  218. 'mobile' => '手机号', 'code' => '验证码', 'area_code' => '国际码', 'auth_id' => '微信授权 id'
  219. ]);
  220. $auth_id = $request->get('auth_id', 0);
  221. $code = $request->get('code');
  222. $mobile = $request->get('mobile');
  223. //防止暴力破解
  224. $msg = $this->isCanLogin($request, $mobile, 'api');
  225. if ($msg) {
  226. return $this->response->fail($msg);
  227. }
  228. $this->storeLoginLog($request, $mobile, 'api');
  229. $area_code = $request->get('area_code', '+86');
  230. switch ($area_code) {
  231. case "+886":
  232. //中国台湾
  233. $this->validateData($request, [
  234. 'mobile' => 'required|mobile_TW',
  235. ], ['mobile' => '手机号']);
  236. break;
  237. case "+853":
  238. //中国澳门
  239. $this->validateData($request, [
  240. 'mobile' => 'required|mobile_OM',
  241. ], ['mobile' => '手机号']);
  242. break;
  243. case "+852":
  244. //中国香港
  245. $this->validateData($request, [
  246. 'mobile' => 'required|mobile_XG',
  247. ], ['mobile' => '手机号']);
  248. break;
  249. case '+86':
  250. default:
  251. //大陆
  252. $this->validateData($request, [
  253. 'mobile' => 'required|mobile',
  254. ], ['mobile' => '手机号']);
  255. $area_code = "+86";
  256. break;
  257. }
  258. $key = "controller:sendLoginValidateCode:mobile:{$area_code}:{$mobile}";
  259. $yun_code = Cache::get($key, false);
  260. if ((string)$yun_code !== (string)$code) abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '验证码不对');
  261. list($token, $user) = $this->userService->handleMobileLogin($mobile, $area_code);
  262. $this->userService->handleBindWechat($auth_id, $user);
  263. Cache::forget($key);
  264. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  265. $token = 'Bearer ' . $token;
  266. $expires_in = auth()->factory()->getTTL() * 60;
  267. return $this->response->success(compact('token', 'expires_in'));
  268. }
  269. /**
  270. * 测试登录
  271. * @param Request $request
  272. * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
  273. * @throws \Illuminate\Validation\ValidationException
  274. * @throws \Prettus\Validator\Exceptions\ValidatorException
  275. */
  276. public function testMobileLogin(Request $request)
  277. {
  278. $this->validateData($request, [
  279. 'mobile' => 'required|mobile',
  280. ], ['mobile' => '手机号']);
  281. $mobile = $request->get('mobile');
  282. if (config("app.env", 'production') === 'production') abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, '非法授权');
  283. list($token, $user) = $this->userService->handleMobileLogin($mobile);
  284. $this->singleLoginSetToken(login_user_id(), $token, 'api');
  285. $token = 'Bearer ' . $token;
  286. $expires_in = auth()->factory()->getTTL() * 60;
  287. return $this->response->success(compact('token', 'expires_in'));
  288. }
  289. }