Files
jabali-panel/app/Http/Controllers/ImpersonationController.php
2026-02-02 03:11:45 +02:00

121 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Models\ImpersonationToken;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ImpersonationController extends Controller
{
/**
* Start impersonation - generates token and redirects to impersonate
* Used by admin panel to initiate impersonation via a clickable link
*/
public function start(Request $request, User $user): RedirectResponse
{
// Use the admin guard to check authentication
$admin = Auth::guard('admin')->user();
// Verify admin has permission to impersonate
if (! $admin || ! $admin->is_admin) {
abort(403, 'Unauthorized');
}
// Cannot impersonate other admins
if ($user->is_admin) {
abort(403, 'Cannot impersonate administrators');
}
// Cannot impersonate inactive users
if (! $user->is_active) {
abort(403, 'Cannot impersonate inactive users');
}
// Create the impersonation token
$token = ImpersonationToken::createForUser($admin, $user, $request->ip());
// Redirect to the impersonation route
return redirect()->route('impersonate', ['token' => $token->token]);
}
public function impersonate(Request $request, string $token): RedirectResponse
{
$impersonationToken = ImpersonationToken::findValidToken($token, $request->ip());
if (! $impersonationToken) {
return redirect()->route('filament.admin.pages.dashboard')
->with('error', 'Invalid or expired impersonation token.');
}
// Mark token as used
$impersonationToken->markAsUsed();
// Get the target user
$targetUser = $impersonationToken->targetUser;
if (! $targetUser || ! $targetUser->is_active) {
return redirect()->route('filament.admin.pages.dashboard')
->with('error', 'User not found or inactive.');
}
// Store the admin ID before any session changes
$adminId = $impersonationToken->admin_id;
// Clear any previous impersonation session data first
// This prevents session corruption when impersonating multiple users
session()->forget('impersonated_by');
session()->forget('impersonation_token_id');
// Directly set the user on the web guard without full logout
// This avoids session invalidation that would affect the admin guard
Auth::guard('web')->setUser($targetUser);
// Update the session with the new user's ID for the web guard
session()->put(Auth::guard('web')->getName(), $targetUser->getAuthIdentifier());
// Update the password hash in session for AuthenticateSession middleware
// This prevents the middleware from logging out the user due to hash mismatch
session()->put('password_hash_web', $targetUser->getAuthPassword());
// Store impersonation info in session
session()->put('impersonated_by', $adminId);
session()->put('impersonation_token_id', $impersonationToken->id);
// Save the session to persist changes
session()->save();
// Redirect to user panel
return redirect()->route('filament.jabali.pages.dashboard');
}
/**
* Stop impersonation and return to admin panel
*/
public function stop(): RedirectResponse
{
// Clear impersonation session data
session()->forget('impersonated_by');
session()->forget('impersonation_token_id');
// Clear the web guard session data without full logout
// This preserves the admin session
session()->forget(Auth::guard('web')->getName());
session()->forget('password_hash_web');
// Clear the user from the web guard
Auth::guard('web')->setUser(null);
// Save session changes
session()->save();
// Redirect back to admin panel
return redirect()->route('filament.admin.pages.dashboard')
->with('success', 'Returned to admin account.');
}
}