Jelajahi Sumber

Fixed OAuth not function and improve the code quality

BrettonYe 1 tahun lalu
induk
melakukan
66d9f22f6e

+ 93 - 71
app/Http/Controllers/OAuthController.php

@@ -13,118 +13,140 @@ use Str;
 
 class OAuthController extends Controller
 {
-    public function simple(string $type): RedirectResponse
+    public function unbind(string $provider): RedirectResponse
     {
-        $info = Socialite::driver($type)->stateless()->user();
-        if ($info) {
-            $user = Auth::user();
-
-            if ($user) {
-                return $this->binding($type, $user, $info);
-            }
+        $user = Auth::user();
 
-            return $this->logging($type, $info);
+        if ($user && $user->userAuths()->whereType($provider)->delete()) {
+            return redirect()->route('profile')->with('successMsg', trans('auth.oauth.unbind_success'));
         }
 
-        return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
+        return redirect()->route('profile')->withErrors(trans('auth.oauth.unbind_failed'));
     }
 
-    private function binding(string $type, User $user, \Laravel\Socialite\Contracts\User $OauthUser): RedirectResponse
+    public function bind(string $provider): RedirectResponse
     {
-        $data = ['type' => $type, 'identifier' => $OauthUser->getId(), 'credential' => $OauthUser->token];
-        if ($user->userAuths()->whereType($type)->updateOrCreate($data)) {
-            return redirect()->route('profile')->with('successMsg', trans('auth.oauth.bind_success'));
-        }
+        config(["services.$provider.redirect" => route('oauth.bind', ['provider' => $provider])]);
+        $authInfo = Socialite::driver($provider)->stateless()->user();
 
-        return redirect()->route('profile')->withErrors(trans('auth.oauth.bind_failed'));
-    }
-
-    private function logging(string $type, \Laravel\Socialite\Contracts\User $OauthUser): RedirectResponse
-    {
-        $user = User::whereUsername($OauthUser->getEmail())->first();
-        if (! isset($user)) {
-            $auth = UserOauth::whereType($type)->whereIdentifier($OauthUser->getId())->first();
-            if (isset($auth)) {
-                $user = $auth->user;
-            }
+        if (! $authInfo) {
+            return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
         }
 
-        if (isset($user)) {
-            Auth::login($user);
-            Helpers::userLoginAction($user, IP::getClientIp()); // 用户登录后操作
+        $user = Auth::user();
 
-            return redirect()->route('login');
+        if (! $user) {
+            return redirect()->route('profile')->withErrors(trans('auth.oauth.bind_failed'));
         }
 
-        return redirect()->route('login')->withErrors(trans('auth.error.not_found_user'));
+        return $this->bindLogic($provider, $user, $authInfo);
     }
 
-    public function login(string $type): RedirectResponse
+    private function bindLogic(string $provider, User $user, \Laravel\Socialite\Contracts\User $authInfo): RedirectResponse
     {
-        $info = Socialite::driver($type)->stateless()->user();
-        if ($info) {
-            return $this->logging($type, $info);
+        $data = [
+            'type' => $provider,
+            'identifier' => $authInfo->getId(),
+            'credential' => $authInfo->token,
+        ];
+
+        $auth = $user->userAuths()->whereType($provider)->first();
+
+        if ($auth) {
+            $user->userAuths()->whereType($provider)->update($data);
+            $message = trans('auth.oauth.rebind_success');
+        } else {
+            $user->userAuths()->create($data);
+            $message = trans('auth.oauth.bind_success');
         }
 
-        return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
+        return redirect()->route('profile')->with('successMsg', $message);
     }
 
-    public function unbind(string $type): RedirectResponse
+    public function register(string $provider): RedirectResponse
     {
-        $user = Auth::user();
-        if ($user && $user->userAuths()->whereType($type)->delete()) {
-            return redirect()->route('profile')->with('successMsg', trans('auth.oauth.unbind_success'));
+        config(["services.$provider.redirect" => route('oauth.register', ['provider' => $provider])]);
+        if (! sysConfig('is_register')) {
+            return redirect()->route('register')->withErrors(trans('auth.register.error.disable'));
         }
 
-        return redirect()->route('profile')->with('successMsg', trans('auth.oauth.unbind_failed'));
-    }
+        if ((int) sysConfig('is_invite_register') === 2) {
+            return redirect()->route('register')->withErrors(trans('validation.required', ['attribute' => trans('auth.invite.attribute')]));
+        }
 
-    public function bind(string $type): RedirectResponse
-    {
-        $info = Socialite::driver($type)->stateless()->user();
+        $registerInfo = Socialite::driver($provider)->stateless()->user();
 
-        if ($info) {
-            $user = Auth::user();
-            if ($user) {
-                return $this->binding($type, $user, $info);
-            }
+        if (! $registerInfo) {
+            return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
+        }
 
-            return redirect()->route('profile')->withErrors(trans('auth.oauth.bind_failed'));
+        $user = User::whereUsername($registerInfo->getEmail())->first();
+
+        if (! $user) {  // 邮箱未被注册
+            $userAuth = UserOauth::whereType($provider)->whereIdentifier($registerInfo->getId())->first();
+
+            if (! $userAuth) { // 第三方账号未被绑定
+                $user = Helpers::addUser($registerInfo->getEmail(), Str::random(), MiB * sysConfig('default_traffic'), (int) sysConfig('default_days'), $registerInfo->getNickname());
+
+                $user->userAuths()->create([
+                    'type' => $provider,
+                    'identifier' => $registerInfo->getId(),
+                    'credential' => $registerInfo->token,
+                ]);
+
+                return $this->handleLogin($user);
+            }
         }
 
-        return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
+        return redirect()->route('login')->withErrors(trans('auth.oauth.registered'));
     }
 
-    public function register(string $type): RedirectResponse
+    private function handleLogin(User $user): RedirectResponse
     {
-        if (! sysConfig('is_register')) {
-            return redirect()->route('register')->withErrors(trans('auth.register.error.disable'));
-        }
+        Auth::login($user);
+        Helpers::userLoginAction($user, IP::getClientIp());
 
-        if ((int) sysConfig('is_invite_register') === 2) { // 必须使用邀请码
-            return redirect()->route('register')->withErrors(trans('validation.required', ['attribute' => trans('auth.invite.attribute')]));
-        }
+        return redirect()->route('login');
+    }
 
-        $OauthUser = Socialite::driver($type)->stateless()->user();
+    public function login(string $provider): RedirectResponse
+    {
+        config(["services.$provider.redirect" => route('oauth.login', ['provider' => $provider])]);
+        $authInfo = Socialite::driver($provider)->stateless()->user();
 
-        if ($OauthUser) {
-            if (User::whereUsername($OauthUser->getEmail())->doesntExist() && UserOauth::whereIdentifier($OauthUser->getId())->doesntExist()) { // 排除重复用户注册
-                $user = Helpers::addUser($OauthUser->getEmail(), Str::random(), MiB * sysConfig('default_traffic'), (int) sysConfig('default_days'), $OauthUser->getNickname());
+        if ($authInfo) {
+            $auth = UserOauth::whereType($provider)->whereIdentifier($authInfo->getId())->first();
 
-                $user->userAuths()->create([
-                    'type' => $type,
-                    'identifier' => $OauthUser->getId(),
-                    'credential' => $OauthUser->token,
-                ]);
+            if ($auth && ($user = $auth->user)) { // 如果第三方登录有记录,直接登录用户
+                return $this->handleLogin($user);
+            }
 
-                Auth::login($user);
+            $user = User::whereUsername($authInfo->getEmail())->first();
 
-                return redirect()->route('login');
+            if ($user) { // 如果用户存在,执行绑定逻辑并登录用户
+                $this->bindLogic($provider, $user, $authInfo);
+
+                return $this->handleLogin($user);
             }
 
-            return redirect()->route('login')->withErrors(trans('auth.oauth.registered'));
+            // 如果用户不存在,则返回错误消息
+            return redirect()->route('login')->withErrors(trans('auth.error.not_found_user'));
         }
 
         return redirect()->route('login')->withErrors(trans('auth.oauth.login_failed'));
     }
+
+    public function redirect(string $provider, string $operation = 'login'): RedirectResponse
+    {
+        $redirectRoutes = [
+            'bind' => 'oauth.bind',
+            'register' => 'oauth.register',
+            'login' => 'oauth.login',
+        ];
+
+        $key = "services.$provider.redirect";
+        config([$key => route($redirectRoutes[$operation], ['provider' => $provider])]);
+
+        return Socialite::driver($provider)->stateless()->redirect();
+    }
 }

+ 4 - 4
resources/views/auth/login.blade.php

@@ -36,14 +36,14 @@
             <div class="line">
                 <span> {{ trans('auth.one-click_login') }} </span>
             </div>
-            @foreach (json_decode(sysConfig('oauth_path')) as $item)
-                @if ($item === 'telegram')
+            @foreach (json_decode(sysConfig('oauth_path')) as $provider)
+                @if ($provider === 'telegram')
                     <div>
                         {!! Socialite::driver('telegram')->getButton() !!}
                     </div>
                 @else
-                    <a class="btn btn-icon btn-pure" href="{{route('oauth.login', ['type' => $item])}}">
-                        <i class="fa-brands {{config('common.oauth.icon')[$item]}} fa-lg" aria-hidden="true"></i>
+                    <a class="btn btn-icon btn-pure" href="{{route('oauth.route', ['provider' => $provider, 'operation' => 'login'])}}">
+                        <i class="fa-brands {{config('common.oauth.icon')[$provider]}} fa-lg" aria-hidden="true"></i>
                     </a>
                 @endif
             @endforeach

+ 4 - 4
resources/views/auth/register.blade.php

@@ -106,10 +106,10 @@
             <div class="line">
                 <span> {{trans('auth.oauth.register')}} </span>
             </div>
-            @foreach (json_decode(sysConfig('oauth_path')) as $item)
-                @if ($item !== 'telegram')
-                    <a class="btn btn-icon btn-pure" href="{{route('oauth.register', ['type' => $item])}}">
-                        <i class="fa-brands {{config('common.oauth.icon')[$item]}} fa-lg" aria-hidden="true"></i>
+            @foreach (json_decode(sysConfig('oauth_path')) as $provider)
+                @if ($provider !== 'telegram')
+                    <a class="btn btn-icon btn-pure" href="{{route('oauth.route', ['provider' => $provider, 'operation' => 'register'])}}">
+                        <i class="fa-brands {{config('common.oauth.icon')[$provider]}} fa-lg" aria-hidden="true"></i>
                     </a>
                 @endif
             @endforeach

+ 8 - 8
resources/views/user/profile.blade.php

@@ -42,22 +42,22 @@
                             <span> {{trans('user.oauth.bind_title')}} </span>
                         </div>
                         <div class="user-socials list-group-gap list-group-full row m-0">
-                            @foreach (json_decode(sysConfig('oauth_path')) as $item)
-                                <a class="list-group-item justify-content-center @if(in_array($item, $auth, true)) col-10 @else col-12 @endif"
-                                   @if($item !== 'telegram') href="{{route('oauth.bind', ['type' => $item])}}" @endif>
-                                    <i class="fa-brands {{ config('common.oauth.icon')[$item] }} fa-lg mr-10" aria-hidden="true"></i> {{ ucfirst($item) }}
+                            @foreach (json_decode(sysConfig('oauth_path')) as $provider)
+                                <a class="list-group-item justify-content-center @if(in_array($provider, $auth, true)) col-10 @else col-12 @endif"
+                                   @if($provider !== 'telegram') href="{{route('oauth.route', ['provider' => $provider, 'operation' => 'bind'])}}" @endif>
+                                    <i class="fa-brands {{ config('common.oauth.icon')[$provider] }} fa-lg mr-10" aria-hidden="true"></i> {{ ucfirst($provider) }}
                                     :
-                                    @if(in_array($item, $auth, true))
+                                    @if(in_array($provider, $auth, true))
                                         <span class="red-600">{{trans('user.oauth.rebind')}}</span>
                                     @else
                                         <span class="grey-500">{{trans('user.oauth.not_bind')}}</span>
                                     @endif
-                                    @if($item === 'telegram')
+                                    @if($provider === 'telegram')
                                         {!! Socialite::driver('telegram')->getButton() !!}
                                     @endif
                                 </a>
-                                @if(in_array($item, $auth, true))
-                                    <a class="col-2 btn btn-block btn-danger my-auto" href="{{route('oauth.unbind', ['type' => $item])}}">{{trans('user.oauth.unbind')}}</a>
+                                @if(in_array($provider, $auth, true))
+                                    <a class="col-2 btn btn-block btn-danger my-auto" href="{{route('oauth.unbind', ['provider' => $provider])}}">{{trans('user.oauth.unbind')}}</a>
                                 @endif
                             @endforeach
                         </div>

+ 5 - 5
routes/web.php

@@ -22,11 +22,11 @@ Route::get('/message/{type}/{msg_id}/show', [MessageController::class, 'index'])
 
 Route::middleware(['isForbidden', 'affiliate', 'isMaintenance'])->group(function () { // 登录相关
     Route::prefix('oauth')->name('oauth.')->controller(OAuthController::class)->group(function () { // 用户第三方登录默认登录/转跳方式
-        Route::get('{type}/login', 'login')->name('login');
-        Route::get('{type}/register', 'register')->name('register');
-        Route::get('{type}/bind', 'bind')->name('bind');
-        Route::get('{type}/unbind', 'unbind')->name('unbind');
-        Route::get('{type}/redirect', 'simple')->name('simple');
+        Route::get('{provider}/redirect/{operation}', 'redirect')->whereIn('operation', ['bind', 'register', 'login'])->name('route'); // 转跳
+        Route::get('{provider}/unbind', 'unbind')->name('unbind'); // 解绑
+        Route::get('{provider}/login', 'login')->name('login'); // 登录 callback
+        Route::get('{provider}/register', 'register')->name('register'); // 注册 callback
+        Route::get('{provider}/bind', 'bind')->name('bind'); // 绑定 callback
     });
 
     Route::controller(AuthController::class)->group(function () {