AuthController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <?php
  2. namespace App\Http\Controllers\V1;
  3. use App\Http\Controllers\Controller;
  4. use App\Http\Requests\MobileLoginRequest;
  5. use App\Http\Requests\WeappAuthorizationRequest;
  6. use App\Http\Requests\WeappUserinfoRequest;
  7. use App\Maps\CacheMap;
  8. use App\Models\Area;
  9. use App\Models\Auth;
  10. use App\Models\User;
  11. use App\Models\UserPhoneDetail;
  12. use App\Repositories\ConfigRepository;
  13. use App\Repositories\InviteNewUserRepository;
  14. use App\Repositories\UserRepository;
  15. use App\Transformers\UserTransformer;
  16. use Carbon\Carbon;
  17. use EasyWeChat\Factory;
  18. use Illuminate\Support\Facades\Cache;
  19. use Illuminate\Support\Facades\Log;
  20. use Tymon\JWTAuth\Facades\JWTAuth;
  21. use Alipay\EasySDK\Kernel\Factory as AliFactory;
  22. use Alipay\EasySDK\Kernel\Config;
  23. use Alipay\EasySDK\Kernel\Util\ResponseChecker;
  24. use Illuminate\Http\Request;
  25. use Illuminate\Support\Facades\DB;
  26. /**
  27. * 小程序权限认证模块
  28. * Class AuthController
  29. * @package App\Http\Controllers\V1
  30. */
  31. class AuthController extends Controller
  32. {
  33. protected $jwt;
  34. protected $userRepository;
  35. /**
  36. * Create a new controller instance.
  37. *
  38. * @return void
  39. */
  40. public function __construct(JWTAuth $jwt, UserRepository $userRepository)
  41. {
  42. parent::__construct();
  43. $this->jwt = $jwt;
  44. $this->userRepository = $userRepository;
  45. }
  46. /**
  47. * 小程序认证
  48. * @param WeappAuthorizationRequest $request
  49. * User: Mead
  50. */
  51. public function xiaoLogin(WeappAuthorizationRequest $request, ConfigRepository $configRepository, InviteNewUserRepository $inviteNewUserRepository)
  52. {
  53. try {
  54. $code = $request->code;
  55. $appid = $request->appid;
  56. $type = (int)$request->get('type', 0); //0微信 1支付宝
  57. $response = [];
  58. $invite_user_id = $request->get('invite_user_id') ?? 0;
  59. switch ($type) {
  60. case Auth::TYPE_WEAPP: //微信
  61. if ($appid !== self::$MERCHANT['wxapp_app_id']) {
  62. return $this->errorBadRequest('app_id is error');
  63. }
  64. $miniProgram = Factory::miniProgram(wechat_mini_config(self::$MERCHANT));
  65. $data = $miniProgram->auth->session($code);
  66. if (isset($data['errcode'])) {
  67. $this->response->errorUnauthorized('code 不正确');
  68. return '';
  69. }
  70. $auth = Auth::where([
  71. ['identifier', '=', $appid],
  72. ['type', '=', Auth::TYPE_WEAPP]
  73. ])->where('credential', $data['openid'])->first();
  74. //注册认证信息
  75. $attributes['type'] = Auth::TYPE_WEAPP;
  76. $attributes['credential'] = $data['openid'];
  77. //授权方式
  78. $source = 1;
  79. //response参数
  80. $response['session_key'] = $data['session_key'];
  81. //来源
  82. $laiyuan = User::REGISTER_SOURCE_WEAPP;
  83. break;
  84. case Auth::TYPE_ALIPAY://支付宝
  85. if ($appid !== self::$MERCHANT['alipaymini_appId']) {
  86. return $this->errorBadRequest('app_id is error');
  87. }
  88. try {
  89. $result = alipay_mini_config(self::$MERCHANT)->base()->oauth()->getToken($code);
  90. } catch (\Throwable $e) {
  91. return $this->errorBadRequest('服务异常');
  92. }
  93. $responseChecker = new ResponseChecker();
  94. if (!($responseChecker->success($result))) {
  95. $this->response->errorBadRequest("调用失败,原因:" . $result->msg . "," . $result->subMsg);
  96. return '';
  97. }
  98. $data = json_decode($result->httpBody, true)['alipay_system_oauth_token_response'];
  99. $auth = Auth::where([
  100. ['identifier', '=', $appid],
  101. ['type', '=', Auth::TYPE_ALIPAY]
  102. ])->where('credential', $data['user_id'])->first();
  103. //注册认证信息
  104. $attributes['type'] = Auth::TYPE_ALIPAY;
  105. $attributes['credential'] = $data['user_id'];
  106. //授权方式
  107. $source = 2;
  108. //来源
  109. $laiyuan = User::REGISTER_SOURCE_ALIPAYMINI;
  110. break;
  111. default:
  112. $this->errorBadRequest('登录类型不存在');
  113. return '';
  114. }
  115. $is_auth = true;
  116. if (!$auth) {
  117. //注册用户
  118. $userInfo = $this->userRepository->getRandomUserInfo();
  119. $userInfo['register_source'] = $laiyuan;
  120. $userInfo['merchant_id'] = self::$MERCHANT_ID;
  121. $userInfo['is_new_user_coupons'] = User::IS_NEW_USER_COUPONS_OK;
  122. $user = User::create($userInfo);
  123. //添加邀请注册活动
  124. if ((int)$invite_user_id != 0) {
  125. $inviteNewUserRepository->create($invite_user_id, $user->id, $source);
  126. }
  127. $attributes['identifier'] = $appid;
  128. $attributes['user_id'] = $user->id;
  129. $attributes['merchant_id'] = self::$MERCHANT_ID;
  130. $attributes['is_verified'] = Auth::VERIFIED_OK;
  131. $auth = Auth::create($attributes);
  132. $is_auth = false;
  133. } else {
  134. $user = $this->userRepository->byIdGetModel($auth->user_id);
  135. }
  136. $phone_detail = $request->get('phone_detail') ?? '';
  137. if (!empty($phone_detail)) {
  138. $detail = json_decode($phone_detail);
  139. if (!empty($detail)) {
  140. UserPhoneDetail::Log($detail, $user->id);
  141. }
  142. }
  143. $token = JWTAuth::fromUser($user);
  144. // 单机登录限制
  145. // app()->redis->hset(CacheMap::SINGLE_LOGIN_API, $user->id, $token);
  146. $response['is_auth'] = $is_auth;
  147. $response['token'] = 'Bearer ' . $token;
  148. $response['exp'] = Carbon::now()->addMinute(JWTAuth::factory()->getTTL())->getTimestamp();
  149. $response['auth_id'] = $auth->id;
  150. $response['user'] = $is_auth ? $user : [];
  151. $response['android_mini_version'] = $configRepository->getMiniAndroidVersion();
  152. $response['ios_mini_version'] = $configRepository->getMiniIosVersion();
  153. return $this->response->array($response);
  154. } catch (\Exception $exception) {
  155. return $this->exception($exception);
  156. }
  157. }
  158. /**
  159. * mobileLogin 手机号登录
  160. *
  161. * @param MobileLoginRequest $request
  162. * @param ConfigRepository $configRepository
  163. * @return
  164. * @author Fx
  165. *
  166. */
  167. public function mobileLogin(MobileLoginRequest $request, ConfigRepository $configRepository)
  168. {
  169. try {
  170. $mobile = $request->get('mobile', null);
  171. $code = $request->get('code', false);
  172. $type = (int)$request->get('type', 1);
  173. $auth_id = (int)$request->get('auth_id', false);
  174. if (!$auth_id) {
  175. $auth_id = $this->user->id;
  176. }
  177. switch ($type) {
  178. case 1:
  179. //微信解析手机号
  180. $session = $request->get('session_key');
  181. $iv = $request->get('iv');
  182. $encryptedData = $request->get('encryptedData');
  183. $miniProgram = Factory::miniProgram(wechat_mini_config(self::$MERCHANT));
  184. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  185. $mobile = $decryptedData['purePhoneNumber'];
  186. break;
  187. case 2:
  188. //短信验证
  189. $v_code = Cache::get("verification_code_{$mobile}", '');
  190. // if (empty($v_code)) {
  191. // return $this->errorNoValidation('短信验证码已过期');
  192. // }
  193. //
  194. // if ((string)$v_code !== (string)$code) {
  195. // return $this->errorNoValidation('短信验证码错误');
  196. // }
  197. break;
  198. case 3:
  199. //支付宝解析手机号
  200. $shouji = AlipayMiniOpenSign(self::$MERCHANT, $request->get('session_key'));
  201. if ($shouji['code'] != 10000) {
  202. $this->errorBadRequest('手机号解析失败');
  203. };
  204. $mobile = $shouji['mobile'];
  205. break;
  206. default:
  207. $this->errorBadRequest('获取手机号类型不存在');
  208. return '';
  209. }
  210. if (!$mobile) {
  211. return $this->errorNoValidation('手机号有误');
  212. }
  213. $user = User::query()->where('merchant_id', self::$MERCHANT_ID)->where('mobile', $mobile)->first();
  214. if (!$user) {
  215. $user_id = $this->user->id;
  216. if (!$user_id) {
  217. return $this->errorNoValidation('找不到该用户');
  218. }
  219. //注册手机号
  220. $this->user->fill([
  221. 'mobile' => $mobile,
  222. 'is_bind_mobile' => User::BIND_MOBILE_OK,
  223. 'nickname' => '闪现-' . rand(100000, 999999),
  224. 'avatar' => "http://resource.bike.hanyiyun.com/logo.png",
  225. 'register_area_id' => $request->get('area_id', 0),
  226. 'register_area' => $request->get('area_id', 0) ? Area::where('id', $request->get('area_id', 0))->value('name') : null
  227. ]);
  228. $re = $this->user->save();
  229. if (!$re) {
  230. return $this->errorNoValidation('用户保存失败');
  231. }
  232. $user = User::query()->where('merchant_id', self::$MERCHANT_ID)->where('id', $user_id)->first();
  233. }
  234. // 新用户1-》没找到手机号-》注册-》信息相等 新用户2-》找到新用户1手机号-》已注册-》信息不相等
  235. $auth = Auth::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth_id)->first();
  236. if (!$auth) {
  237. return $this->errorBadRequest('授权有误请重新授权');
  238. }
  239. if ($auth->user_id != $user->id) {
  240. DB::beginTransaction();
  241. //已经注册过得 更新同一个用户
  242. $upauth = Auth::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth_id)->update(['user_id' => $user->id]);
  243. //删除多的user记录
  244. $userde = User::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth->user_id)->delete();
  245. if (!$upauth && !$userde) {
  246. DB::rollBack();
  247. } else {
  248. DB::commit();
  249. }
  250. }
  251. $phone_detail = $request->get('phone_detail', false);
  252. if ($phone_detail) {
  253. $detail = json_decode($phone_detail);
  254. if (!empty($detail)) {
  255. UserPhoneDetail::Log($detail, $user->id);
  256. }
  257. }
  258. $token = JWTAuth::fromUser($user);
  259. // 单机登录限制
  260. app()->redis->hset(CacheMap::SINGLE_LOGIN_API, $user->id, $token);
  261. return $this->response->array([
  262. 'token' => 'Bearer ' . $token,
  263. 'exp' => Carbon::now()->addMinute(JWTAuth::factory()->getTTL())->getTimestamp(),
  264. // 'auth_id' => $auth->id ?? '',
  265. 'user' => $user,
  266. 'android_mini_version' => $configRepository->getMiniAndroidVersion(),
  267. 'ios_mini_version' => $configRepository->getMiniIosVersion(),
  268. ]);
  269. } catch (\Exception $exception) {
  270. return $this->exception($exception);
  271. }
  272. }
  273. /**
  274. * mobileLogin 手机号登录 正式的时候开启
  275. *
  276. * @param MobileLoginRequest $request
  277. * @param ConfigRepository $configRepository
  278. * @return
  279. * @author Fx
  280. *
  281. */
  282. public function mobileLogin_zhengshi(MobileLoginRequest $request, ConfigRepository $configRepository)
  283. {
  284. try {
  285. $mobile = $request->get('mobile', null);
  286. $code = $request->get('code', false);
  287. $type = (int)$request->get('type', 1);
  288. $auth_id = (int)$request->get('auth_id', false);
  289. if (!$auth_id) {
  290. $auth_id = $this->user->id;
  291. }
  292. switch ($type) {
  293. case 1:
  294. //微信解析手机号
  295. $session = $request->get('session_key');
  296. $iv = $request->get('iv');
  297. $encryptedData = $request->get('encryptedData');
  298. $miniProgram = Factory::miniProgram(wechat_mini_config(self::$MERCHANT));
  299. $decryptedData = $miniProgram->encryptor->decryptData($session, $iv, $encryptedData);
  300. $mobile = $decryptedData['purePhoneNumber'];
  301. break;
  302. case 2:
  303. //短信验证
  304. $v_code = Cache::get("verification_code_{$mobile}", '');
  305. if (empty($v_code)) {
  306. return $this->errorNoValidation('短信验证码已过期');
  307. }
  308. if ((string)$v_code !== (string)$code) {
  309. return $this->errorNoValidation('短信验证码错误');
  310. }
  311. break;
  312. case 3:
  313. //支付宝解析手机号
  314. $shouji = AlipayMiniOpenSign(self::$MERCHANT, $request->get('session_key'));
  315. if ($shouji['code'] != 10000) {
  316. $this->errorBadRequest('手机号解析失败');
  317. };
  318. $mobile = $shouji['mobile'];
  319. break;
  320. default:
  321. $this->errorBadRequest('获取手机号类型不存在');
  322. return '';
  323. }
  324. if (!$mobile) {
  325. return $this->errorNoValidation('手机号有误');
  326. }
  327. $user = User::query()->where('merchant_id', self::$MERCHANT_ID)->where('mobile', $mobile)->first();
  328. if (!$user) {
  329. $user_id = $this->user()->id;
  330. if (!$user_id) {
  331. return $this->errorNoValidation('找不到该用户');
  332. }
  333. //注册手机号
  334. $this->user->fill([
  335. 'mobile' => $mobile,
  336. 'is_bind_mobile' => User::BIND_MOBILE_OK,
  337. 'nickname' => '闪现-' . rand(100000, 999999),
  338. 'avatar' => "http://resource.bike.hanyiyun.com/logo.png",
  339. 'register_area_id' => $request->get('area_id', 0),
  340. 'register_area' => $request->get('area_id', 0) ? Area::where('id', $request->get('area_id', 0))->value('name') : null
  341. ]);
  342. $re = $this->user->save();
  343. if (!$re) {
  344. return $this->errorNoValidation('用户保存失败');
  345. }
  346. $user = User::query()->where('merchant_id', self::$MERCHANT_ID)->where('id', $user_id)->first();
  347. }
  348. // 新用户1-》没找到手机号-》注册-》信息相等 新用户2-》找到新用户1手机号-》已注册-》信息不相等
  349. $auth = Auth::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth_id)->first();
  350. if (!$auth) {
  351. return $this->errorBadRequest('授权有误请重新授权');
  352. }
  353. if ($auth->user_id != $user->id) {
  354. DB::beginTransaction();
  355. //已经注册过得 更新同一个用户
  356. $upauth = Auth::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth_id)->update(['user_id' => $user->id]);
  357. //删除多的user记录
  358. $userde = User::where('merchant_id', self::$MERCHANT_ID)->where('id', $auth->user_id)->delete();
  359. if (!$upauth && !$userde) {
  360. DB::rollBack();
  361. } else {
  362. DB::commit();
  363. }
  364. }
  365. $phone_detail = $request->get('phone_detail', false);
  366. if ($phone_detail) {
  367. $detail = json_decode($phone_detail);
  368. if (!empty($detail)) {
  369. UserPhoneDetail::Log($detail, $user->id);
  370. }
  371. }
  372. $token = JWTAuth::fromUser($user);
  373. // 单机登录限制
  374. app()->redis->hset(CacheMap::SINGLE_LOGIN_API, $user->id, $token);
  375. return $this->response->array([
  376. 'token' => 'Bearer ' . $token,
  377. 'exp' => Carbon::now()->addMinute(JWTAuth::factory()->getTTL())->getTimestamp(),
  378. // 'auth_id' => $auth->id ?? '',
  379. 'user' => $user,
  380. 'android_mini_version' => $configRepository->getMiniAndroidVersion(),
  381. 'ios_mini_version' => $configRepository->getMiniIosVersion(),
  382. ]);
  383. } catch (\Exception $exception) {
  384. return $this->exception($exception);
  385. }
  386. }
  387. /**
  388. * 更新用户基本信息
  389. * User: Mead
  390. */
  391. public function weappUserInfoSync(WeappUserinfoRequest $request)
  392. {
  393. try {
  394. $this->user->fill([
  395. 'nickname' => $request->get('nickName'),
  396. 'gender' => $request->get('gender', 0),
  397. 'country' => $request->get('country', 'China'),
  398. 'province' => $request->get('province', 'Henan'),
  399. 'city' => $request->get('city', 'Zhengzhou'),
  400. 'avatar' => $request->get('avatarUrl', 'http://resource.bike.hanyiyun.com/logo.png') ?? "http://resource.bike.hanyiyun.com/logo.png",
  401. 'language' => $request->get('language', 'zh_CN'),
  402. 'register_area_id' => $request->get('area_id', 0),
  403. 'register_area' => $request->get('area_id', 0) ? Area::where('id', $request->get('area_id', 0))->value('name') : '',
  404. 'is_register' => User::REGISTER_OK
  405. ]);
  406. $this->user->save();
  407. return $this->response->item($this->user, UserTransformer::class);
  408. } catch (\Exception $exception) {
  409. return $this->exception($exception);
  410. }
  411. }
  412. /**
  413. * 获取当前登录用户
  414. * @return
  415. * User: Mead
  416. */
  417. public function loginUser()
  418. {
  419. try {
  420. return $this->response->item($this->user, UserTransformer::class);
  421. } catch (\Exception $exception) {
  422. return $this->exception($exception);
  423. }
  424. }
  425. }