From 8290bafb0479f7c3b934731d206829cb7ef76ef2 Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Wed, 15 Aug 2018 14:22:13 +0100 Subject: [PATCH] #5: It's now possible to sign in/register with a Facebook account, and to link the FB account to an existing account by entering the account's password. --- app/Http/Controllers/Auth/LoginController.php | 94 ++++++++++++++++--- .../Controllers/Auth/RegisterController.php | 28 +++++- resources/lang/en/auth.php | 3 + .../themes/base/auth/v2_unified.blade.php | 22 ++++- .../themes/base/partials/login.blade.php | 43 +++++---- .../themes/base/partials/register.blade.php | 26 +++-- routes/web.php | 2 + 7 files changed, 173 insertions(+), 45 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 715e3fb..88cd5f1 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -43,6 +43,31 @@ class LoginController extends Controller $this->middleware('guest', ['except' => 'logout']); } + protected function attemptLogin(Request $request) + { + $isSuccessful = $this->guard()->attempt($this->credentials($request)); + + if ($isSuccessful) + { + /** @var User $user */ + $user = $this->guard()->user(); + + // Update the social media ID if successful login and it was referred by the SSO provider + $loginData = $request->getSession()->get('ssoLoginData'); + if (!is_null($loginData)) + { + unset($loginData['name']); + unset($loginData['email']); + $user->fill($loginData); + $user->save(); + + $request->getSession()->remove('ssoLoginData'); + } + } + + return $isSuccessful; + } + protected function credentials(Request $request) { $result = $request->only($this->username(), 'password'); @@ -62,7 +87,31 @@ class LoginController extends Controller { return Theme::render('auth.v2_unified', [ 'active_tab' => 'login', - 'info' => $request->session()->get('info') + 'info' => $request->session()->get('info'), + 'is_sso' => false + ]); + } + + /** + * Show the application's login form (for a social media-linked account). + * + * @return \Illuminate\Http\Response + */ + public function showLoginFormSso(Request $request) + { + // Social media login info + $loginData = $request->getSession()->get('ssoLoginData'); + if (is_null($loginData)) + { + // No SSO data in session, use the normal login screen + return redirect(route('login')); + } + + return Theme::render('auth.v2_unified', [ + 'active_tab' => 'login', + 'info' => $request->session()->get('info'), + 'is_sso' => true, + 'login_data' => $loginData ]); } @@ -86,29 +135,52 @@ class LoginController extends Controller { $socialite = $this->setSocialiteConfigs(); $facebookUser = $socialite->driver('facebook')->user(); - $user = User::where('facebook_id', $facebookUser->id)->first(); - if (is_null($user)) + return $this->processSocialMediaLogin($request, 'facebook_id', $facebookUser); + } + + private function processSocialMediaLogin(Request $request, $socialMediaIdField, $socialMediaUser) + { + $userBySocialMediaId = User::where($socialMediaIdField, $socialMediaUser->getId())->first(); + + if (!is_null($userBySocialMediaId)) { - $request->getSession()->put('registerData', [ - 'name' => $facebookUser->name, - 'email' => $facebookUser->email, - 'facebook_id' => $facebookUser->id, + // We have an existing user for this Facebook ID - log them in + $this->guard()->login($userBySocialMediaId); + return redirect(route('home')); + } + + $userByEmailAddress = User::where('email', $socialMediaUser->email)->first(); + + if (!is_null($userByEmailAddress)) + { + // We have an existing user with the e-mail address associated with the Facebook account + // Prompt for the password for that account + $request->getSession()->put('ssoLoginData', [ + 'name' => $socialMediaUser->getName(), + 'email' => $socialMediaUser->getEmail(), + $socialMediaIdField => $socialMediaUser->getId(), 'is_activated' => true ]); - return redirect(route('register')); + return redirect(route('auth.login_sso')); } - $this->guard()->login($user); + // We don't have an existing user - prompt for registration + $request->getSession()->put('ssoRegisterData', [ + 'name' => $socialMediaUser->getName(), + 'email' => $socialMediaUser->getEmail(), + $socialMediaIdField => $socialMediaUser->getId(), + 'is_activated' => true + ]); - return redirect(route('home')); + return redirect(route('auth.register_sso')); } private function setSocialiteConfigs() { // Force Socialite to use our config from the database instead of hard-coded in config/services.php - $socialite = app()->make('Laravel\Socialite\Contracts\Factory'); + $socialite = app()->make(\Laravel\Socialite\Contracts\Factory::class); $socialite->extend( 'facebook', function ($app) use ($socialite) { diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 932765d..1155fa7 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -115,10 +115,11 @@ class RegisterController extends Controller $userData = $request->all(); // Social media login info - $registerData = $request->getSession()->get('registerData'); + $registerData = $request->getSession()->get('ssoRegisterData'); if (!is_null($registerData)) { $userData = array_merge($registerData, $userData); + $request->getSession()->remove('ssoRegisterData'); } /** @var User $user */ @@ -150,16 +151,35 @@ class RegisterController extends Controller return redirect(route('home')); } + return Theme::render('auth.v2_unified', [ + 'active_tab' => 'register', + 'is_sso' => false + ]); + } + + /** + * Show the application registration form (for a social media-linked account). + * + * @return \Illuminate\Http\Response + */ + public function showRegistrationFormSso(Request $request) + { + if (!UserConfig::get('allow_self_registration')) + { + return redirect(route('home')); + } + // Social media login info - $registerData = $request->getSession()->get('registerData'); + $registerData = $request->getSession()->get('ssoRegisterData'); if (is_null($registerData)) { - $registerData['name'] = ''; - $registerData['email'] = ''; + // No SSO data in session, use the normal registration screen + return redirect(route('register')); } return Theme::render('auth.v2_unified', [ 'active_tab' => 'register', + 'is_sso' => true, 'register_data' => $registerData ]); } diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index 172bd1a..545f1b6 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -23,7 +23,10 @@ return [ 'change_password_action' => 'Change password', 'change_password_title' => 'Change your password', 'email_password_login' => 'Alternatively, login with your e-mail address and password:', + 'email_password_login_sso' => 'The social media account you logged in with has not been used here before, however an account with the e-mail address already exists.', + 'email_password_login_sso_2' => 'Please enter the password for this account to link your social media account to it.', 'email_password_register' => 'Alternatively, create an account using your e-mail address and a password:', + 'email_password_register_sso' => 'Please confirm your name and set a password for your account:', 'forgot_password_action' => 'Send Reset E-mail', 'forgot_password_link' => 'Forgotten your password?', 'forgot_password_title' => 'Send password reset link', diff --git a/resources/views/themes/base/auth/v2_unified.blade.php b/resources/views/themes/base/auth/v2_unified.blade.php index f1d7f24..200d7f3 100644 --- a/resources/views/themes/base/auth/v2_unified.blade.php +++ b/resources/views/themes/base/auth/v2_unified.blade.php @@ -8,13 +8,25 @@
diff --git a/resources/views/themes/base/partials/login.blade.php b/resources/views/themes/base/partials/login.blade.php index e61c2aa..3fd6848 100644 --- a/resources/views/themes/base/partials/login.blade.php +++ b/resources/views/themes/base/partials/login.blade.php @@ -1,10 +1,14 @@ -

@lang('auth.social_login')

-

- - {{----}} -

+@if (!$is_sso) +

@lang('auth.social_login')

+

+ +

-

@lang('auth.email_password_login')

+

@lang('auth.email_password_login')

+@else +

@lang('auth.email_password_login_sso')

+

@lang('auth.email_password_login_sso_2')

+@endif
{{ csrf_field() }} @@ -13,7 +17,12 @@
- + @if ($is_sso) + + + @else + + @endif @if ($errors->has('email'))
@@ -27,7 +36,7 @@
- + @if ($errors->has('password'))
@@ -37,16 +46,18 @@
-
-
-
-
- - + @if (!$is_sso) +
+
+
+
+ + +
-
+ @endif
diff --git a/resources/views/themes/base/partials/register.blade.php b/resources/views/themes/base/partials/register.blade.php index ac55fc4..7c6e3cc 100644 --- a/resources/views/themes/base/partials/register.blade.php +++ b/resources/views/themes/base/partials/register.blade.php @@ -1,10 +1,13 @@ -

@lang('auth.social_register')

-

- - {{----}} -

+@if (!$is_sso) +

@lang('auth.social_register')

+

+ +

-

@lang('auth.email_password_register')

+

@lang('auth.email_password_register')

+@else +

@lang('auth.email_password_register_sso')

+@endif {{ csrf_field() }} @@ -13,7 +16,7 @@
- + @if ($errors->has('name'))
@@ -27,7 +30,12 @@
- + @if ($is_sso) + + + @else + + @endif @if ($errors->has('email'))
@@ -41,7 +49,7 @@
- + @if ($errors->has('password'))
diff --git a/routes/web.php b/routes/web.php index 1110f8d..3521f5a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -77,6 +77,8 @@ Route::group(['prefix' => 'install'], function () { // Social media SSO Route::get('login/facebook', 'Auth\LoginController@redirectToFacebook')->name('login.facebook'); Route::get('login/facebook/callback', 'Auth\LoginController@handleFacebookCallback')->name('login_callback.facebook'); +Route::get('login/sso', 'Auth\LoginController@showLoginFormSso')->name('auth.login_sso'); +Route::get('register/sso', 'Auth\RegisterController@showRegistrationFormSso')->name('auth.register_sso'); // Gallery Route::get('/', 'Gallery\DefaultController@index')->name('home');