Put back google social login
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 32s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s

This commit is contained in:
Deon George 2024-08-23 17:28:00 +10:00
parent 89fb347806
commit b877a2b673
8 changed files with 337 additions and 119 deletions

View File

@ -24,6 +24,6 @@ class CollectionOrNull implements CastsAttributes
*/ */
public function set(Model $model, string $key, mixed $value, array $attributes): mixed public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{ {
return $value->count() ? json_encode($value) : NULL; return count($value) ? json_encode($value) : NULL;
} }
} }

View File

@ -3,10 +3,15 @@
namespace App\Http\Controllers\Auth; namespace App\Http\Controllers\Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Laravel\Socialite\Facades\Socialite; use Laravel\Socialite\Facades\Socialite;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Mail\SocialLink;
use App\Models\{ProviderOauth,ProviderToken,User,UserOauth}; use App\Models\{ProviderOauth,ProviderToken,User,UserOauth};
class SocialLoginController extends Controller class SocialLoginController extends Controller
@ -22,54 +27,58 @@ class SocialLoginController extends Controller
$openiduser = Socialite::with($provider)->user(); $openiduser = Socialite::with($provider)->user();
if (! $openiduser) if (! $openiduser)
return redirect('/home')->with('error','No user details obtained.'); return redirect('/home')
->with('error','No user details obtained.');
$oo = ProviderOauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]); $oo = ProviderOauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);
// See if this user has connected and linked previously // See if this user has connected and linked previously
$aoo = $oo->users->where('userid',$openiduser->id); $aoo = $oo->users->where('userid',$openiduser->id);
if ($aoo->count() == 1) { if ($aoo->count() === 1) {
$aoo = $aoo->first(); $aoo = $aoo->first();
if ((is_null($user=$aoo->user) AND (is_null($aoo->account) OR is_null($user=$aoo->account->user))) OR ! $user->active) { if ((is_null($user=$aoo->user) && (is_null($aoo->account) || is_null($user=$aoo->account->user))) || ! $user->active) {
if (! $user) { if (! $user)
$user = User::where('email',$openiduser->email)->first(); $user = User::where('email',$openiduser->email)->first();
}
if (! $user OR ! $user->active) { if ((! $user) || (! $user->active))
return redirect('/login')->with('error','Invalid account, or account inactive, please contact an admin.'); return redirect('/login')
} ->with('error','Invalid account, or account inactive, please contact an admin.');
return $this->link($provider,$aoo,$user); return $this->link($provider,$aoo,$user);
} }
// All Set to login // All Set to login
Auth::login($user,FALSE); Auth::login($user);
// If there are too many users, then we have a problem // If there are too many users, then we have a problem
} elseif ($aoo->count() > 1) { } elseif ($aoo->count() > 1) {
return redirect('/login')->with('error','Seems you have multiple oauth IDs, please contact an admin.'); return redirect('/login')
->with('error','Seems you have multiple oauth IDs, please contact an admin.');
// User is using OAUTH for the first time. // User is using OAUTH for the first time.
} else { } else {
$uo = User::active()->where('email',$openiduser->email); $uo = User::active()->where('email',$openiduser->email);
// See if their is an account with this email address // See if their is an account with this email address
if ($uo->count() == 1) { if ($uo->count() === 1) {
$aoo = new UserOauth; $aoo = new UserOauth;
$aoo->userid = $openiduser->id; $aoo->userid = $openiduser->id;
$aoo->oauth_data = $openiduser->user; $aoo->oauth_data = $openiduser->user;
$oo->users()->save($aoo); $oo->users()->save($aoo);
return $this->link($provider,$aoo,$uo->first()); return $this->link($provider,$aoo,$uo->first());
// If there are too many users, then we have a problem // If there are too many users, then we have a problem
} elseif ($uo->count() > 1) { } elseif ($uo->count() > 1) {
return redirect('/login')->with('error','Seems you have multiple accounts, please contact an admin.'); return redirect('/login')
->with('error','Seems you have multiple accounts, please contact an admin.');
} else { } else {
return redirect('/login')->with('error','Seems you dont have an account with that email, please contact an admin.'); return redirect('/login')
->with('error','Seems you dont have an account with that email, please contact an admin.');
} }
} }
@ -82,7 +91,8 @@ class SocialLoginController extends Controller
$openiduser = Socialite::with($provider)->user(); $openiduser = Socialite::with($provider)->user();
if (! $openiduser) if (! $openiduser)
return redirect('/home')->with('error','No user details obtained.'); return redirect('/home')
->with('error','No user details obtained.');
$po = ProviderOauth::where('name',$provider)->singleOrFail(); $po = ProviderOauth::where('name',$provider)->singleOrFail();
@ -101,4 +111,51 @@ class SocialLoginController extends Controller
->intended('/home') ->intended('/home')
->with('success','Token refreshed.'); ->with('success','Token refreshed.');
} }
/**
* We have identified the user and oauth, just need them to confirm the link
*
* @param $provider
* @param UserOauth $ao
* @param User $uo
* @return View
*/
public function link($provider,UserOauth $ao,User $uo): View
{
// @note If this is sent now (send()), it results in the caller to be executed a second time (handleProviderCallback()).
Mail::to($uo->email)->queue(new SocialLink($ao));
return view('theme.backend.adminlte.auth.social_link')
->with('oauthid',$ao->id)
->with('provider',$provider);
}
public function linkcomplete(Request $request,$provider)
{
// Load our oauth id
$aoo = UserOauth::findOrFail($request->post('oauthid'));
// Check our email matches
if (Arr::get($aoo->oauth_data,'email','invalid') !== $request->post('email'))
return redirect('/login')
->with('error','Account details didnt match to make link.');
// Check our token matches
if ($aoo->link_token !== $request->post('token'))
return redirect('/login')
->with('error','Token details didnt match to make link.');
// Load our email.
$uo = User::where('email',$request->post('email'))->firstOrFail();
// Incase we have an existing record with a different oauthid
UserOauth::where('user_id',$uo->id)->delete();
$aoo->user_id = $uo->id;
$aoo->save();
Auth::login($uo);
return redirect()
->intended('/home');
}
} }

48
app/Mail/SocialLink.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use App\Models\{Site,User,UserOauth};
class SocialLink extends Mailable
{
use Queueable, SerializesModels;
public string $token;
public Site $site;
public ?User $user;
/**
* Create a new message instance.
*
* @param UserOauth $o
*/
public function __construct(UserOauth $o)
{
$this->site = $o->site;
$this->token = $o->link_token;
$this->user = $o->user;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
Config::set('site',$this->site);
return $this
->markdown('mail.system.social_link')
->subject('Link your Account')
->with([
'site'=>$this->site,
]);
}
}

View File

@ -118,4 +118,12 @@ return [
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
'social' => [
'google' => [
'name' => 'Google',
'id' => 'google',
'class' => 'btn-danger',
'icon' => 'fab fa-google',
],
],
]; ];

View File

@ -42,6 +42,12 @@ return [
'guid' => env('EZYPAY_GUID'), 'guid' => env('EZYPAY_GUID'),
], ],
'google' => [
'client_id' => env('AUTH_GOOGLE_CLIENT_ID'),
'client_secret' => env('AUTH_GOOGLE_SECRET'),
'redirect' => '/auth/google/callback',
],
'provider' => [ 'provider' => [
'intuit' => [ 'intuit' => [
'api'=> \Intuit\API::class, 'api'=> \Intuit\API::class,

View File

@ -0,0 +1,21 @@
@component('mail::message',['site'=>$site,'heading'=>'Link Your Account'])
Hi {{ isset($user) ? $user->full_name.',' : '' }}
A request was made to link your account to a social login.
If you didnt make this request, you can ignore this, and the request will be ignored.
If you did make the request, then please enter the code displayed below.
@component('mail::table')
{{ $token }}
@endcomponent
Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password.
Thanks,
{{ config('mail.from.name') }}
@component('mail::subcopy')
If you didnt make this request, you can safely ignore this email - no change was made to your account, nor was it accessed by an unauthorised person.
@endcomponent
@endcomponent

View File

@ -0,0 +1,76 @@
@extends('adminlte::layouts.auth')
@section('htmlheader_title')
Link Account
@endsection
@section('content')
<div class="login-box">
<div class="login-logo">
<a>{!! config('app.name_html_long') !!}</a>
</div>
<div class="alert alert-success">
<strong>NOTE:</strong> Link your account.<br><br>
<ul>
<li>An email has been sent to you with a token, please use those details here:</li>
</ul>
</div>
@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> {{ trans('adminlte_lang::message.someproblems') }}<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="card">
<div class="card-body login-card-body">
<p class="login-box-msg">Link your account</p>
<form method="post" action="{{ url('/auth/'.$provider.'/linkcomplete') }}">
@csrf
<input type="hidden" name="oauthid" value="{{ $oauthid }}">
<div class="input-group mb-3">
<input type="email" name="email" class="form-control" placeholder="Email">
<div class="input-group-append">
<span class="fa fa-envelope input-group-text"></span>
</div>
</div>
<div class="input-group mb-3">
<input type="password" name="token" class="form-control" placeholder="Token">
<div class="input-group-append">
<span class="fa fa-lock input-group-text"></span>
</div>
</div>
<div class="row">
<div class="col-8">
&nbsp;
</div>
<div class="col-4">
<button type="submit" name="submit" class="btn btn-sm btn-primary float-right">Link</button>
</div>
</div>
</form>
<p class="mb-1">
<a name="reset" href="{{ url('/password/reset') }}">{{ trans('adminlte_lang::message.forgotpassword') }}</a>
</p>
@isset($register)
<p class="mb-0">
<a href="register.html" class="text-center">Register a new account</a>
</p>
@endisset
</div>
</div>
</div>
@endsection

View File

@ -62,6 +62,8 @@ Route::get('pay/paypal/capture',[PaypalController::class,'capture']);
Route::get('auth/{socialProvider}',[SocialLoginController::class,'redirectToProvider']); Route::get('auth/{socialProvider}',[SocialLoginController::class,'redirectToProvider']);
Route::get('auth/{socialProvider}/callback',[SocialLoginController::class,'handleProviderCallback']); Route::get('auth/{socialProvider}/callback',[SocialLoginController::class,'handleProviderCallback']);
Route::get('auth/{socialProvider}/token',[SocialLoginController::class,'handleBearerTokenCallback']); Route::get('auth/{socialProvider}/token',[SocialLoginController::class,'handleBearerTokenCallback']);
Route::get('auth/{socialProvider}/link',[SocialLoginController::class,'link']);
Route::post('auth/{socialProvider}/linkcomplete',[SocialLoginController::class,'linkcomplete']);
// Return from user switch // Return from user switch
Route::get('admin/switch/stop',[SwitchUserController::class,'switch_stop']) Route::get('admin/switch/stop',[SwitchUserController::class,'switch_stop'])