penambahan login degnan Google
This commit is contained in:
parent
979fa95f36
commit
f18b7454a8
160
app/Http/Controllers/Auth/GoogleAuthController.php
Normal file
160
app/Http/Controllers/Auth/GoogleAuthController.php
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\DeviceIp;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class GoogleAuthController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Redirect to Google OAuth
|
||||||
|
*/
|
||||||
|
public function redirect()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return Socialite::driver('google')->redirect();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Session::flash('error', get_phrase('Google authentication is currently unavailable. Please try again later.'));
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Google OAuth callback
|
||||||
|
*/
|
||||||
|
public function callback()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$googleUser = Socialite::driver('google')->user();
|
||||||
|
|
||||||
|
// Validate required data
|
||||||
|
if (!$googleUser->getEmail()) {
|
||||||
|
Session::flash('error', get_phrase('Google account email is required. Please ensure your Google account has an email address.'));
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find existing user by email
|
||||||
|
$existingUser = User::where('email', $googleUser->getEmail())->first();
|
||||||
|
|
||||||
|
if ($existingUser) {
|
||||||
|
// Update existing user with Google data if missing
|
||||||
|
if (!$existingUser->google_id) {
|
||||||
|
$existingUser->update([
|
||||||
|
'google_id' => $googleUser->getId(),
|
||||||
|
'avatar' => $googleUser->getAvatar() ?? $existingUser->avatar,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($existingUser);
|
||||||
|
return $this->handlePostLogin($existingUser);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Create new user with your existing field structure
|
||||||
|
$newUser = User::create([
|
||||||
|
'name' => $googleUser->getName() ?? $this->generateNameFromEmail($googleUser->getEmail()),
|
||||||
|
'email' => $googleUser->getEmail(),
|
||||||
|
'google_id' => $googleUser->getId(),
|
||||||
|
'password' => null, // No password for Google-authenticated users
|
||||||
|
'role' => 'student',
|
||||||
|
'status' => 1,
|
||||||
|
'photo' => $googleUser->getAvatar(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (get_settings('student_email_verification') != 1) {
|
||||||
|
$user_data['email_verified_at'] = Carbon::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($newUser);
|
||||||
|
Session::flash('success', get_phrase('Account created successfully! Welcome to our platform.'));
|
||||||
|
return $this->handlePostLogin($newUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Session::flash('error', get_phrase('Authentication failed. Please try again or use another method.'));
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle post-login logic (device tracking, etc.)
|
||||||
|
*/
|
||||||
|
private function handlePostLogin($user)
|
||||||
|
{
|
||||||
|
request()->session()->regenerate();
|
||||||
|
|
||||||
|
// Track device limitation (same as your existing login)
|
||||||
|
if (Auth::check() && $user->role != 'admin') {
|
||||||
|
$current_ip = request()->getClientIp();
|
||||||
|
$session_id = request()->session()->getId();
|
||||||
|
$current_user_agent = base64_encode($user->id . request()->header('user-agent'));
|
||||||
|
$allowed_devices = get_settings('device_limitation') ?? 1;
|
||||||
|
$logged_in_devices = DeviceIp::where('user_id', $user->id)->get();
|
||||||
|
|
||||||
|
if ($logged_in_devices->where('user_agent', '!=', $current_user_agent)->count() < $allowed_devices) {
|
||||||
|
if ($logged_in_devices->where('user_agent', $current_user_agent)->count() == 0) {
|
||||||
|
DeviceIp::insert([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'ip_address' => $current_ip,
|
||||||
|
'session_id' => $session_id,
|
||||||
|
'user_agent' => $current_user_agent,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
DeviceIp::where('user_id', $user->id)
|
||||||
|
->where('user_agent', $current_user_agent)
|
||||||
|
->update([
|
||||||
|
'session_id' => $session_id,
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$logged_in_oldest_row = DeviceIp::where('user_id', $user->id)->orderBy('id', 'desc')->first();
|
||||||
|
$data = [
|
||||||
|
'verification_link' => route('login', ['user_agent' => $logged_in_oldest_row->user_agent])
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
Mail::send('email.new_device_login_verification', $data, function ($message) use($user) {
|
||||||
|
$message->to($user->email, $user->name)->subject('New login confirmation');
|
||||||
|
});
|
||||||
|
|
||||||
|
Auth::guard('web')->logout();
|
||||||
|
request()->session()->invalidate();
|
||||||
|
request()->session()->regenerateToken();
|
||||||
|
|
||||||
|
Session::flash('success', get_phrase('A confirmation email has been sent. Please check your inbox to confirm access to this account from this device.'));
|
||||||
|
return redirect(route('login'));
|
||||||
|
} catch (\Swift_TransportException $e) {
|
||||||
|
Session::flash('error', 'We could not send the email. Please try again later.');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Session::flash('error', 'Something went wrong. Please try again.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::guard('web')->logout();
|
||||||
|
request()->session()->invalidate();
|
||||||
|
request()->session()->regenerateToken();
|
||||||
|
return redirect(route('login'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->intended('/dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a name from email if Google name is not available
|
||||||
|
*/
|
||||||
|
private function generateNameFromEmail($email)
|
||||||
|
{
|
||||||
|
$name = strstr($email, '@', true);
|
||||||
|
return ucfirst(str_replace(['.', '_'], ' ', $name));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
'password',
|
'password',
|
||||||
'role',
|
'role',
|
||||||
'status',
|
'status',
|
||||||
|
'google_id',
|
||||||
'email_verified_at'
|
'email_verified_at'
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
"intervention/image": "^2.7",
|
"intervention/image": "^2.7",
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^11.0",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
|
"laravel/socialite": "*",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"paytm/paytmchecksum": "^1.1",
|
"paytm/paytmchecksum": "^1.1",
|
||||||
"pbmedia/laravel-ffmpeg": "^8.6",
|
"pbmedia/laravel-ffmpeg": "^8.6",
|
||||||
|
|||||||
2284
composer.lock
generated
2284
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -30,5 +30,10 @@ return [
|
|||||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
],
|
],
|
||||||
|
'google' => [
|
||||||
|
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||||
|
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||||
|
'redirect' => env('GOOGLE_REDIRECT_URL'),
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@ -248,7 +248,6 @@ button:focus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border: none;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -406,7 +406,7 @@ img {
|
|||||||
.google-login-btn:hover {
|
.google-login-btn:hover {
|
||||||
background: linear-gradient(45deg, #f8f9fa 0%, #e9ecef 100%);
|
background: linear-gradient(45deg, #f8f9fa 0%, #e9ecef 100%);
|
||||||
border-color: var(--color-1);
|
border-color: var(--color-1);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-1px);
|
||||||
color: #333;
|
color: #333;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
box-shadow: 0 4px 15px rgba(66, 133, 244, 0.2);
|
box-shadow: 0 4px 15px rgba(66, 133, 244, 0.2);
|
||||||
@ -428,6 +428,7 @@ img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.eBtn {
|
.eBtn {
|
||||||
|
border: none;
|
||||||
padding: 12px 30px;
|
padding: 12px 30px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -443,9 +444,11 @@ img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.eBtn:hover {
|
.eBtn:hover {
|
||||||
|
border: 1px solid;
|
||||||
background-position: right center;
|
background-position: right center;
|
||||||
border-color: #0330c4 !important;
|
border-color: var(--color-1);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-2px);
|
||||||
|
color: #333 !important;
|
||||||
box-shadow: 0 6px 20px rgba(2, 25, 110, 0.25);
|
box-shadow: 0 6px 20px rgba(2, 25, 110, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +463,7 @@ img {
|
|||||||
|
|
||||||
.gradient:hover {
|
.gradient:hover {
|
||||||
background-position: right center;
|
background-position: right center;
|
||||||
color: #001151;
|
color: #001151 !important;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2903,7 +2906,6 @@ html .ui-button.ui-state-disabled:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.global-form button {
|
.global-form button {
|
||||||
border: none;
|
|
||||||
padding: 12px 30px;
|
padding: 12px 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7790,3 +7792,5 @@ textarea.lms-form-control {
|
|||||||
/* ===================================================================
|
/* ===================================================================
|
||||||
Tutor Details CSS End
|
Tutor Details CSS End
|
||||||
====================================================================*/
|
====================================================================*/
|
||||||
|
|
||||||
|
px
|
||||||
|
|||||||
@ -75,7 +75,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="#" class="list text-18px d-inline-flex" data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight" aria-controls="offcanvasRight">
|
{{-- <a href="#" class="list text-18px d-inline-flex" data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight" aria-controls="offcanvasRight">
|
||||||
<span class="d-block h-100 w-100" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ get_phrase('AI Assistant') }}">
|
<span class="d-block h-100 w-100" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ get_phrase('AI Assistant') }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="22" height="22" x="0" y="0" viewBox="0 0 64 64" style="enable-background:new 0 0 512 512" xml:space="preserve" class="">
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="22" height="22" x="0" y="0" viewBox="0 0 64 64" style="enable-background:new 0 0 512 512" xml:space="preserve" class="">
|
||||||
<g>
|
<g>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a> --}}
|
||||||
|
|
||||||
<div class="dropdown ol-icon-dropdown ol-icon-dropdown-transparent" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ get_phrase('Help Center') }}">
|
<div class="dropdown ol-icon-dropdown ol-icon-dropdown-transparent" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ get_phrase('Help Center') }}">
|
||||||
<button class="btn ol-btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<button class="btn ol-btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Google Login Button --}}
|
{{-- Google Login Button --}}
|
||||||
<a href="javascript:void(0)" onclick="error('{{ get_phrase("Feature still in development 🚧") }}')" class="google-login-btn w-100">
|
<a href="{{ route('google.redirect') }}" class="google-login-btn w-100">
|
||||||
<img src="{{ asset('assets/frontend/default/image/Google.png') }}" alt="Google Logo">
|
<img src="{{ asset('assets/frontend/default/image/Google.png') }}" alt="Google Logo">
|
||||||
{{ get_phrase('Login with Google') }}
|
{{ get_phrase('Login with Google') }}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -104,7 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Google Login Button --}}
|
{{-- Google Login Button --}}
|
||||||
<a href="javascript:void(0)" onclick="error('{{ get_phrase("Feature still in development 🚧") }}')" class="google-login-btn w-100">
|
<a href="{{ route('google.redirect') }}" class="google-login-btn w-100">
|
||||||
<img src="{{ asset('assets/frontend/default/image/Google.png') }}" alt="Google Logo">
|
<img src="{{ asset('assets/frontend/default/image/Google.png') }}" alt="Google Logo">
|
||||||
{{ get_phrase('Sign Up with Google') }}
|
{{ get_phrase('Sign Up with Google') }}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="@if ($current_route == 'my_bookings' || $current_route == 'booking_invoice') active @endif">
|
{{-- <li class="@if ($current_route == 'my_bookings' || $current_route == 'booking_invoice') active @endif">
|
||||||
<a href="{{ route('my_bookings', ['tab' => 'live-upcoming']) }}" class="bootcamp-sidebar-icon text-capitalize">
|
<a href="{{ route('my_bookings', ['tab' => 'live-upcoming']) }}" class="bootcamp-sidebar-icon text-capitalize">
|
||||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="m-0">
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="m-0">
|
||||||
<path d="M1.67188 7.5V6.66667C1.67188 4.16667 3.33854 2.5 5.83854 2.5H14.1719C16.6719 2.5 18.3385 4.16667 18.3385 6.66667V13.3333C18.3385 15.8333 16.6719 17.5 14.1719 17.5H13.3385" stroke="#6B7385" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" />
|
<path d="M1.67188 7.5V6.66667C1.67188 4.16667 3.33854 2.5 5.83854 2.5H14.1719C16.6719 2.5 18.3385 4.16667 18.3385 6.66667V13.3333C18.3385 15.8333 16.6719 17.5 14.1719 17.5H13.3385" stroke="#6B7385" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
@ -51,7 +51,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
{{ get_phrase('My Bookings') }}
|
{{ get_phrase('My Bookings') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li> --}}
|
||||||
|
|
||||||
<li class="@if ($current_route == 'my.team.packages' || $current_route == 'my.team.packages.details' || $current_route == 'team.package.invoice') active @endif">
|
<li class="@if ($current_route == 'my.team.packages' || $current_route == 'my.team.packages.details' || $current_route == 'team.package.invoice') active @endif">
|
||||||
<a href="{{ route('my.team.packages') }}">
|
<a href="{{ route('my.team.packages') }}">
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use App\Http\Controllers\Auth\AuthenticatedSessionController;
|
|||||||
use App\Http\Controllers\Auth\ConfirmablePasswordController;
|
use App\Http\Controllers\Auth\ConfirmablePasswordController;
|
||||||
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
|
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
|
||||||
use App\Http\Controllers\Auth\EmailVerificationPromptController;
|
use App\Http\Controllers\Auth\EmailVerificationPromptController;
|
||||||
|
use App\Http\Controllers\Auth\GoogleAuthController;
|
||||||
use App\Http\Controllers\Auth\NewPasswordController;
|
use App\Http\Controllers\Auth\NewPasswordController;
|
||||||
use App\Http\Controllers\Auth\PasswordController;
|
use App\Http\Controllers\Auth\PasswordController;
|
||||||
use App\Http\Controllers\Auth\PasswordResetLinkController;
|
use App\Http\Controllers\Auth\PasswordResetLinkController;
|
||||||
@ -34,6 +35,11 @@ Route::middleware('guest')->group(function () {
|
|||||||
|
|
||||||
Route::post('reset-password', [NewPasswordController::class, 'store'])
|
Route::post('reset-password', [NewPasswordController::class, 'store'])
|
||||||
->name('password.store');
|
->name('password.store');
|
||||||
|
|
||||||
|
// Google OAuth Routes
|
||||||
|
Route::get('/auth/google/redirect', [GoogleAuthController::class, 'redirect'])->name('google.redirect');
|
||||||
|
Route::get('/auth/google/callback', [GoogleAuthController::class, 'callback'])->name('google.callback');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware('auth')->group(function () {
|
Route::middleware('auth')->group(function () {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user