Spaces:
Running
Running
File size: 6,479 Bytes
b2dcf0f e7550e0 b2dcf0f e7550e0 8d9fa4b e7550e0 8d9fa4b e7550e0 30d67d5 e7550e0 1322e11 b2dcf0f 1322e11 b2dcf0f 1322e11 b2dcf0f 6773345 b2dcf0f d7511e4 1322e11 b2dcf0f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | <?php
namespace App\Http\Middleware;
use App\Domain\Identity\JwtTokenService;
use App\Domain\Identity\RbacService;
use App\Domain\Identity\SessionRepository;
use App\Domain\Identity\UserRepository;
use App\Shared\Http\ApiResponse;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class AuthenticateAccessToken
{
public function __construct(
private readonly JwtTokenService $jwt,
private readonly UserRepository $users,
private readonly SessionRepository $sessions,
private readonly RbacService $rbac,
) {
}
public function handle(Request $request, Closure $next)
{
// ββ Staging auth bypass ββββββββββββββββββββββββββββββββββββββββββββββ
// When AUTH_BYPASS=true: if a valid Bearer JWT is present, use real auth
// so member and admin identities are distinct. Fall back to the bypass
// actor (first DB user) when no token is provided or the token cannot be
// decoded / the sub user cannot be found.
if (config('app.auth_bypass', false)) {
$token = $this->extractBearerToken($request);
if ($token !== null) {
try {
$claims = $this->jwt->decode($token);
$userId = (string) ($claims->sub ?? '');
if ($userId !== '') {
$user = $this->users->findById($userId);
if ($user !== null) {
$request->attributes->set('actor_user', $user);
$request->attributes->set('actor_user_id', $userId);
$request->attributes->set('actor_session_id', (string) ($claims->sid ?? 'bypass-jwt'));
$request->attributes->set('actor_roles', $this->rbac->rolesForUser($userId));
$request->attributes->set('actor_permissions', $this->rbac->permissionsForUser($userId));
return $next($request);
}
}
} catch (Throwable) {
// Invalid JWT β fall through to bypass actor
}
}
$bypass = DB::table('users')->whereNull('deleted_at')->orderBy('id')->first();
$userId = $bypass !== null ? (string) $bypass->id : 'staging-bypass';
$request->attributes->set('actor_user', $bypass);
$request->attributes->set('actor_user_id', $userId);
$request->attributes->set('actor_session_id', 'bypass');
$request->attributes->set('actor_roles', $bypass !== null ? $this->rbac->rolesForUser($userId) : ['SUPER_ADMIN']);
$request->attributes->set('actor_permissions', $bypass !== null ? $this->rbac->permissionsForUser($userId) : ['SUPER_ADMIN_ACCESS']);
return $next($request);
}
$token = $this->extractBearerToken($request);
if ($token === null) {
return ApiResponse::error('UNAUTHORIZED', 'Authentication is required.', [], 401);
}
try {
$claims = $this->jwt->decode($token);
} catch (Throwable) {
return ApiResponse::error('UNAUTHORIZED', 'Authentication token is invalid or expired.', [], 401);
}
$userId = (string) ($claims->sub ?? '');
$sessionId = (string) ($claims->sid ?? '');
$user = $this->users->findById($userId);
$session = $this->sessions->findActiveById($sessionId);
if ($user === null || $session === null || $session->user_id !== $userId) {
return ApiResponse::error('UNAUTHORIZED', 'Authentication token is invalid or expired.', [], 401);
}
if ($user->disabled_at !== null || $user->user_status === 'DISABLED') {
return ApiResponse::error('USER_DISABLED', 'This user account is disabled.', [], 403);
}
if (in_array(strtoupper((string) ($user->portal_status ?? '')), ['SUSPENDED', 'DISABLED'], true)) {
return ApiResponse::error('PORTAL_ACCESS_DISABLED', 'This portal account is not active.', [], 403);
}
$request->attributes->set('actor_user', $user);
$request->attributes->set('actor_user_id', $userId);
$request->attributes->set('actor_session_id', $sessionId);
$request->attributes->set('actor_roles', $this->rbac->rolesForUser($userId));
$request->attributes->set('actor_permissions', $this->rbac->permissionsForUser($userId));
return $next($request);
}
private function extractBearerToken(Request $request): ?string
{
$candidates = [
$request->headers->get('X-Authorization'),
$request->headers->get('Authorization'),
$request->server('HTTP_X_AUTHORIZATION'),
$request->server('HTTP_AUTHORIZATION'),
$request->server('REDIRECT_HTTP_AUTHORIZATION'),
$request->server('Authorization'),
$_SERVER['HTTP_X_AUTHORIZATION'] ?? null,
$_SERVER['HTTP_AUTHORIZATION'] ?? null,
$_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? null,
$_SERVER['Authorization'] ?? null,
];
if (function_exists('getallheaders')) {
$headers = getallheaders();
$candidates[] = $headers['X-Authorization'] ?? $headers['x-authorization'] ?? null;
$candidates[] = $headers['Authorization'] ?? $headers['authorization'] ?? null;
}
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
$candidates[] = $headers['X-Authorization'] ?? $headers['x-authorization'] ?? null;
$candidates[] = $headers['Authorization'] ?? $headers['authorization'] ?? null;
}
foreach ($candidates as $candidate) {
$value = trim((string) ($candidate ?? ''));
if ($value === '') {
continue;
}
if (preg_match('/^Bearer\s+(.+)$/i', $value, $matches) === 1) {
$token = trim($matches[1]);
if ($token !== '') {
return $token;
}
}
if (preg_match('/^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$/', $value) === 1) {
return $value;
}
}
return null;
}
}
|