OAuthController.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\Invite;
  4. use App\Models\User;
  5. use App\Models\UserOauth;
  6. use App\Utils\Helpers;
  7. use App\Utils\IP;
  8. use Hashids\Hashids;
  9. use Illuminate\Http\RedirectResponse;
  10. use Laravel\Socialite\Facades\Socialite;
  11. use Str;
  12. class OAuthController extends Controller
  13. {
  14. public function unbind(string $provider): RedirectResponse
  15. {
  16. $user = auth()->user();
  17. if ($user && $user->userAuths()->whereType($provider)->delete()) {
  18. return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('user.oauth.unbind')]));
  19. }
  20. return redirect()->back()->withErrors(trans('common.failed_item', ['attribute' => trans('user.oauth.unbind')]));
  21. }
  22. public function bind(string $provider): RedirectResponse
  23. {
  24. config(["services.$provider.redirect" => route('oauth.bind', ['provider' => $provider])]);
  25. $authInfo = Socialite::driver($provider)->stateless()->user();
  26. if (! $authInfo) {
  27. return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
  28. }
  29. $user = auth()->user();
  30. if (! $user) {
  31. return redirect()->back()->withErrors(trans('common.failed_item', ['attribute' => trans('user.oauth.bind')]));
  32. }
  33. return $this->bindLogic($provider, $user, $authInfo);
  34. }
  35. private function bindLogic(string $provider, User $user, \Laravel\Socialite\Contracts\User $authInfo): RedirectResponse
  36. {
  37. $data = [
  38. 'type' => $provider,
  39. 'identifier' => $authInfo->getId(),
  40. 'credential' => $authInfo->token,
  41. ];
  42. $auth = $user->userAuths()->whereType($provider)->first();
  43. if ($auth) {
  44. $user->userAuths()->whereType($provider)->update($data);
  45. $message = trans('common.success_item', ['attribute' => trans('user.oauth.rebind')]);
  46. } else {
  47. $user->userAuths()->create($data);
  48. $message = trans('common.success_item', ['attribute' => trans('user.oauth.bind')]);
  49. }
  50. return redirect()->back()->with('successMsg', $message);
  51. }
  52. public function register(string $provider): RedirectResponse
  53. {
  54. config(["services.$provider.redirect" => route('oauth.register', ['provider' => $provider])]);
  55. if (! sysConfig('is_register')) {
  56. return redirect()->route('register')->withErrors(trans('auth.register.error.disable'));
  57. }
  58. if ((int) sysConfig('is_invite_register') === 2) {
  59. return redirect()->route('register')->withErrors(trans('validation.required', ['attribute' => trans('user.invite.attribute')]));
  60. }
  61. $registerInfo = Socialite::driver($provider)->stateless()->user();
  62. if (! $registerInfo) {
  63. return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
  64. }
  65. $user = User::whereUsername($registerInfo->getEmail())->first();
  66. if (! $user) { // 邮箱未被注册
  67. $userAuth = UserOauth::whereType($provider)->whereIdentifier($registerInfo->getId())->first();
  68. if (! $userAuth) { // 第三方账号未被绑定
  69. // 获取邀请信息
  70. $affArr = $this->getAff();
  71. $inviter_id = $affArr['inviter_id'];
  72. // 计算流量值(包括邀请奖励流量)
  73. $transfer_enable = MiB * ((int) sysConfig('default_traffic') + ($inviter_id ? (int) sysConfig('referral_traffic') : 0));
  74. // 创建用户并传入邀请者 ID
  75. $user = Helpers::addUser($registerInfo->getEmail(), Str::random(), $transfer_enable, (int) sysConfig('default_days'), $inviter_id, $registerInfo->getNickname(), 1);
  76. // 更新邀请码(如果使用了邀请码)
  77. if ($affArr['code_id'] && sysConfig('is_invite_register')) {
  78. Invite::find($affArr['code_id'])?->update(['invitee_id' => $user->id, 'status' => 1]);
  79. }
  80. // 清除邀请人Cookie
  81. cookie()->unqueue('register_aff');
  82. // 给邀请人增加流量(如果有的话)
  83. if ($inviter_id) {
  84. $referralUser = User::find($inviter_id);
  85. if ($referralUser && $referralUser->expiration_date >= date('Y-m-d')) {
  86. $referralUser->incrementData(sysConfig('referral_traffic') * MiB);
  87. }
  88. }
  89. $user->userAuths()->create([
  90. 'type' => $provider,
  91. 'identifier' => $registerInfo->getId(),
  92. 'credential' => $registerInfo->token,
  93. ]);
  94. return $this->handleLogin($user);
  95. }
  96. }
  97. return redirect()->route('login')->withErrors(trans('auth.oauth.registered'));
  98. }
  99. private function getAff(): array
  100. { // 获取邀请信息
  101. $data = ['inviter_id' => null, 'code_id' => 0]; // 邀请人ID 与 邀请码ID
  102. // 检查cookie中的邀请信息(通过Affiliate中间件设置)
  103. $cookieAff = request()?->cookie('register_aff');
  104. if ($cookieAff) {
  105. $data['inviter_id'] = $this->setInviter($cookieAff);
  106. }
  107. return $data;
  108. }
  109. private function setInviter(string|int $aff): ?int
  110. {
  111. $uid = 0;
  112. if (is_numeric($aff)) {
  113. $uid = (int) $aff;
  114. } else {
  115. $decode = (new Hashids(sysConfig('affiliate_link_salt'), 8))->decode($aff);
  116. if ($decode) {
  117. $uid = $decode[0];
  118. }
  119. }
  120. return $uid && User::whereId($uid)->exists() ? $uid : null;
  121. }
  122. private function handleLogin(User $user): RedirectResponse
  123. {
  124. auth()->login($user);
  125. Helpers::userLoginAction($user, IP::getClientIp());
  126. return redirect()->route('login');
  127. }
  128. public function login(string $provider): RedirectResponse
  129. {
  130. config(["services.$provider.redirect" => route('oauth.login', ['provider' => $provider])]);
  131. $authInfo = Socialite::driver($provider)->stateless()->user();
  132. if ($authInfo) {
  133. $auth = UserOauth::whereType($provider)->whereIdentifier($authInfo->getId())->first();
  134. if ($auth && ($user = $auth->user)) { // 如果第三方登录有记录,直接登录用户
  135. return $this->handleLogin($user);
  136. }
  137. $user = User::whereUsername($authInfo->getEmail())->first();
  138. if ($user) { // 如果用户存在,执行绑定逻辑并登录用户
  139. $this->bindLogic($provider, $user, $authInfo);
  140. return $this->handleLogin($user);
  141. }
  142. // 如果用户不存在,则返回错误消息
  143. return redirect()->route('login')->withErrors(trans('auth.error.not_found_user'));
  144. }
  145. return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
  146. }
  147. public function redirect(string $provider, string $operation = 'login'): RedirectResponse
  148. {
  149. $redirectRoutes = [
  150. 'bind' => 'oauth.bind',
  151. 'register' => 'oauth.register',
  152. 'login' => 'oauth.login',
  153. ];
  154. $key = "services.$provider.redirect";
  155. config([$key => route($redirectRoutes[$operation], ['provider' => $provider])]);
  156. return Socialite::driver($provider)->stateless()->redirect();
  157. }
  158. }