sls/app/Http/Controllers/LoginController.php
2026-07-08 15:28:17 +05:30

206 lines
7.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\User;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class LoginController extends Controller
{
/**
* Show the login selection screen or redirect if already authenticated.
*/
public function showLoginForm()
{
if (Auth::check()) {
return $this->redirectUserBasedOnRole(Auth::user());
}
return view('auth.login');
}
/**
* Show the administrator login screen.
*/
public function showAdminLoginForm()
{
if (Auth::check()) {
return $this->redirectUserBasedOnRole(Auth::user());
}
return view('auth.admin-login');
}
/**
* Handle Email & Password login for Administrators.
*/
public function adminLogin(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials, $request->boolean('remember'))) {
$user = Auth::user();
// Enforce that only administrators can log in via credentials
if ($user->role === 'admin') {
$request->session()->regenerate();
return redirect()->intended(route('admin.dashboard'))
->with('success', 'Logged in successfully as Admin.');
}
// Log out unauthorized user immediately
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return back()->withErrors([
'email' => 'Access denied. The provided credentials do not belong to an Administrator.',
])->onlyInput('email');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
])->onlyInput('email');
}
/**
* Redirect the user to the Microsoft Azure authentication page.
*/
public function redirectToMicrosoft()
{
try {
return Socialite::driver('microsoft')->redirect();
} catch (Exception $e) {
\Illuminate\Support\Facades\Log::error('Microsoft Authentication redirect failed', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
return redirect()->route('login')->with('error', 'Unable to redirect to Microsoft: ' . $e->getMessage());
}
}
/**
* Obtain the user information from Microsoft Azure.
*/
public function handleMicrosoftCallback(Request $request)
{
try {
$microsoftUser = Socialite::driver('microsoft')->user();
} catch (Exception $e) {
\Illuminate\Support\Facades\Log::error('Microsoft Authentication callback failed', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
return redirect()->route('login')->with('error', 'Microsoft Authentication failed or was cancelled: ' . $e->getMessage());
}
$email = $microsoftUser->getEmail();
$isSentientGeeks = str_ends_with($email, '@sentientgeeks.com') || str_ends_with($email, '@sentientgeeks.in');
// Search for user by microsoft_id first, then by email
$user = User::where('microsoft_id', $microsoftUser->getId())->first();
if (!$user) {
$user = User::where('email', $email)->first();
}
if ($user) {
if ($user->is_blocked) {
return redirect()->route('login')->with('error', 'Your account has been blocked. Please contact the administrator.');
}
if ($user->role === 'admin') {
return redirect()->route('admin.login')->with('error', 'Security protocol: Administrators are restricted to email and password authentication only.');
}
// Update existing user with Microsoft data if not already set
$user->update([
'microsoft_id' => $microsoftUser->getId(),
'microsoft_token' => $microsoftUser->token,
'microsoft_refresh_token' => $microsoftUser->refreshToken ?? $user->microsoft_refresh_token,
'avatar' => $microsoftUser->getAvatar() ?? $user->avatar,
]);
} else {
// Block registration if domain is not allowed
if (!$isSentientGeeks) {
return redirect()->route('login')->with('error', 'Access denied. Only @sentientgeeks.com and @sentientgeeks.in users are allowed to register.');
}
// Create a new User (defaults to 'user' role)
$user = User::create([
'name' => $microsoftUser->getName() ?? explode('@', $email)[0],
'email' => $email,
'microsoft_id' => $microsoftUser->getId(),
'microsoft_token' => $microsoftUser->token,
'microsoft_refresh_token' => $microsoftUser->refreshToken ?? null,
'avatar' => $microsoftUser->getAvatar(),
'role' => 'user',
]);
}
Auth::login($user, true);
$request->session()->regenerate();
return $this->redirectUserBasedOnRole($user);
}
public function logout(Request $request)
{
$user = Auth::user();
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
// Redirect to Microsoft's logout URL to log the user out of Microsoft as well
try {
$tenant = config('services.microsoft.tenant', 'common');
$logoutUrl = "https://login.microsoftonline.com/{$tenant}/oauth2/v2.0/logout";
$params = [
'post_logout_redirect_uri' => route('login'),
];
if ($user && $user->email) {
// Pass logout_hint to bypass Microsoft's "Pick an account" selection screen
$params['logout_hint'] = $user->email;
}
$microsoftLogoutUrl = $logoutUrl . '?' . http_build_query($params);
return redirect($microsoftLogoutUrl);
} catch (\Exception $e) {
return redirect()->route('login')->with('success', 'Logged out successfully.');
}
}
/**
* Handle front-channel logout from Microsoft.
*/
public function frontChannelLogout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
// Microsoft renders this in an iframe. A simple 200 response is expected.
return response('Logged out from SingleLogin', 200);
}
/**
* Helper method to redirect user depending on their role.
*/
protected function redirectUserBasedOnRole($user)
{
if ($user->role === 'admin') {
return redirect()->route('admin.dashboard');
}
return redirect()->route('dashboard');
}
}