Phase 1: API + Frontend Skelett
This commit is contained in:
113
www/api.fahrschuldesk.de/app/Http/Middleware/AuthMiddleware.php
Normal file
113
www/api.fahrschuldesk.de/app/Http/Middleware/AuthMiddleware.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* JWT Authentication Middleware
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Support\Database;
|
||||
use App\Support\Response;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class AuthMiddleware
|
||||
{
|
||||
private string $jwtSecret;
|
||||
|
||||
public function __construct(string $jwtSecret)
|
||||
{
|
||||
$this->jwtSecret = $jwtSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate JWT token and attach user to request
|
||||
*/
|
||||
public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$authHeader = $request->getHeaderLine('Authorization');
|
||||
|
||||
if (empty($authHeader) || !str_starts_with($authHeader, 'Bearer ')) {
|
||||
return Response::unauthorized($response ?? $handler->handle($request), 'No token provided');
|
||||
}
|
||||
|
||||
$token = substr($authHeader, 7);
|
||||
|
||||
try {
|
||||
$decoded = JWT::decode($token, new Key($this->jwtSecret, 'HS256'));
|
||||
|
||||
if ($decoded->type !== 'access') {
|
||||
return Response::unauthorized($handler->handle($request), 'Invalid token type');
|
||||
}
|
||||
|
||||
// Attach auth info to request
|
||||
$request = $request->withAttribute('auth', [
|
||||
'id' => $decoded->sub,
|
||||
'type' => $decoded->user_type,
|
||||
'token' => $decoded,
|
||||
]);
|
||||
|
||||
return $handler->handle($request);
|
||||
} catch (\Firebase\JWT\ExpiredException $e) {
|
||||
return Response::unauthorized($handler->handle($request), 'Token expired');
|
||||
} catch (\Exception $e) {
|
||||
return Response::unauthorized($handler->handle($request), 'Invalid token');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the user is a platform admin
|
||||
*/
|
||||
public static function platformAdmin(ServerRequestInterface $request): ?ResponseInterface
|
||||
{
|
||||
$auth = $request->getAttribute('auth');
|
||||
|
||||
if (!$auth || $auth['type'] !== 'platform_admin') {
|
||||
$response = new \Slim\Psr7\Response();
|
||||
return Response::forbidden($response, 'Platform admin access required');
|
||||
}
|
||||
|
||||
return null; // OK
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the user is a tenant user (any type)
|
||||
*/
|
||||
public static function tenantUser(ServerRequestInterface $request): ?ResponseInterface
|
||||
{
|
||||
$auth = $request->getAttribute('auth');
|
||||
|
||||
if (!$auth || $auth['type'] !== 'user') {
|
||||
$response = new \Slim\Psr7\Response();
|
||||
return Response::forbidden($response, 'Tenant user access required');
|
||||
}
|
||||
|
||||
return null; // OK
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the user has a specific user type
|
||||
*/
|
||||
public static function requireUserType(ServerRequestInterface $request, array $types): ?ResponseInterface
|
||||
{
|
||||
$auth = $request->getAttribute('auth');
|
||||
|
||||
if (!$auth || $auth['type'] !== 'user') {
|
||||
$response = new \Slim\Psr7\Response();
|
||||
return Response::forbidden($response, 'User access required');
|
||||
}
|
||||
|
||||
$user = Database::fetch('SELECT user_type FROM users WHERE id = $1', [$auth['id']]);
|
||||
|
||||
if (!$user || !in_array($user['user_type'], $types)) {
|
||||
$response = new \Slim\Psr7\Response();
|
||||
return Response::forbidden($response, 'Insufficient permissions');
|
||||
}
|
||||
|
||||
return null; // OK
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user