From 5e66387666c248488e5f8d6368bda89b68e688ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Abdala=20Bohaczk?= Date: Mon, 24 Feb 2025 21:45:04 -0300 Subject: [PATCH 1/2] jwt token implement --- app/Controllers/BlockController.php | 16 ++- app/Controllers/ClassRoomController.php | 20 +++- app/Controllers/HomeController.php | 1 - app/Controllers/SchedulesController.php | 22 +++- app/Controllers/SubjectController.php | 14 ++- app/Controllers/UsersController.php | 12 +- app/Middleware/AdminRole.php | 37 +++++- app/Middleware/Authenticate.php | 47 ++++++-- composer.json | 3 + composer.lock | 70 +++++++++++- config/bootstrap.php | 3 +- config/routes.php | 144 ++++++++++++------------ lib/Authentication/Auth.php | 56 ++++++--- 13 files changed, 329 insertions(+), 116 deletions(-) diff --git a/app/Controllers/BlockController.php b/app/Controllers/BlockController.php index 63613f7..df43894 100644 --- a/app/Controllers/BlockController.php +++ b/app/Controllers/BlockController.php @@ -6,6 +6,7 @@ use Core\Http\Controllers\Controller; use Core\Http\Request; +use Exception; use function array_map; use function is_null; use function json_encode; @@ -30,8 +31,7 @@ public function create(Request $request): void { $image = ($_FILES['photo'] ?? null); $params = $request->getBody(); - unset($params['PHPSESSID']); - $block = new Block($params); + $block = new Block(['name' => $params['name']]); if ($block->isValid()) { if ($block->save()) { @@ -111,10 +111,20 @@ public function imageUpdate(Request $request): void public function destroy(Request $request): void { + try { $params = $request->getParams(); $block = Block::findById($params['id']); + + if (!$block) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } + $block->destroy(); - echo json_encode(['success' => 'deletado com sucesso']); + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/ClassRoomController.php b/app/Controllers/ClassRoomController.php index 0e5473a..1ebe5a5 100644 --- a/app/Controllers/ClassRoomController.php +++ b/app/Controllers/ClassRoomController.php @@ -8,8 +8,10 @@ use Core\Database\Database; use Core\Http\Controllers\Controller; use Core\Http\Request; +use Exception; use PDO; +use PDOException; use function is_null; use function json_encode; @@ -88,10 +90,20 @@ public function update(Request $request): void public function destroy(Request $request): void { - $params = $request->getParams(); - $block = Block::findById($params['id']); - $block->destroy(); + try { + $params = $request->getParams(); + $classroom = ClassRoom::findById($params['id']); + + if (!$classroom) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } - echo json_encode(['success' => 'deletado com sucesso']); + $classroom->destroy(); + + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/HomeController.php b/app/Controllers/HomeController.php index 5aed60c..3322be8 100644 --- a/app/Controllers/HomeController.php +++ b/app/Controllers/HomeController.php @@ -21,7 +21,6 @@ class HomeController extends Controller { public function index(Request $request): void { - $params = $request->getParams(); $date = date('Y-m-d'); if (isset($params['date'])) { diff --git a/app/Controllers/SchedulesController.php b/app/Controllers/SchedulesController.php index b0b645d..8058adc 100644 --- a/app/Controllers/SchedulesController.php +++ b/app/Controllers/SchedulesController.php @@ -3,6 +3,7 @@ namespace App\Controllers; use App\Enums\RolesEnum; +use App\Models\Block; use App\Models\ClassRoom; use App\Models\Roles; use App\Models\Schedules; @@ -52,9 +53,8 @@ public function index(): void public function byProfessorId(Request $request): void { - - $id = $request->getParams()['id']; - $allSchedules = Schedules::byProfessorId($id); + $userId = (Auth::user()->id); + $allSchedules = Schedules::byProfessorId($userId); $schedulesArray = array_map(function ($schedule) { return [ 'id' => $schedule->id, @@ -259,9 +259,21 @@ public function roomChange(Request $request): void public function delete(Request $request): void { + try { $params = $request->getParams(); - $subject = Schedules::findById($params['id']); - $subject->destroy(); + $schedule = Schedules::findById($params['id']); + + if (!$schedule) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } + + $schedule->destroy(); + + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } public function validatesDateConflict(Schedules $schedule): bool diff --git a/app/Controllers/SubjectController.php b/app/Controllers/SubjectController.php index 5722c35..698f4b1 100644 --- a/app/Controllers/SubjectController.php +++ b/app/Controllers/SubjectController.php @@ -2,10 +2,12 @@ namespace App\Controllers; +use App\Models\Block; use App\Models\Subject; use Core\Http\Controllers\Controller; use Core\Http\Request; +use Exception; use function array_map; use function is_null; use function json_encode; @@ -84,10 +86,20 @@ public function update(Request $request): void public function destroy(Request $request): void { + try { $params = $request->getParams(); $subject = Subject::findById($params['id']); + + if (!$subject) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } + $subject->destroy(); - echo json_encode(['success' => 'deletado com sucesso']); + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/UsersController.php b/app/Controllers/UsersController.php index e4207e8..6864773 100644 --- a/app/Controllers/UsersController.php +++ b/app/Controllers/UsersController.php @@ -6,9 +6,11 @@ use App\Models\User; use Core\Http\Controllers\Controller; use Core\Http\Request; +use Firebase\JWT\JWT; use Lib\Authentication\Auth; use function array_map; +use function getenv; use function hash; use function json_encode; use function password_hash; @@ -39,10 +41,18 @@ public function login(Request $request): void if ($user && $user->authenticate($params['password'])) { Auth::login($user); + $payload = [ + "iss" => "http://localhost", + "aud" => "http://localhost", + "iat" => time(), + "exp" => time() + (60 * 60), + "user_id" => $user->id + ]; + $token = JWT::encode($payload,$_ENV['PASSWORD_KEY_HASH'], 'HS256'); echo json_encode([ 'success' => 'Logado com sucesso', 'role' => $user->roleName(), - 'token' => $user->id + 'token' => $token ]); } else { http_response_code(400); diff --git a/app/Middleware/AdminRole.php b/app/Middleware/AdminRole.php index 8e83191..df98b8a 100644 --- a/app/Middleware/AdminRole.php +++ b/app/Middleware/AdminRole.php @@ -2,19 +2,54 @@ namespace App\Middleware; +use App\Models\User; use Core\Exceptions\HTTPException; use Core\Http\Middleware\Middleware; use Core\Http\Request; +use Exception; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; use Lib\Authentication\Auth; +use function dd; +use function getenv; +use function http_response_code; +use function json_encode; +use function str_replace; class AdminRole implements Middleware { public function handle(Request $request): void { - if (Auth::user()->role_id != 1) { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + http_response_code(401); + echo json_encode(["error" => "Token não fornecido"]); + exit(); + } + + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = $this->validatesToken($token); + $user = User::findById($data['user_id']); + + if ($user->role_id != 1) { header('Content-Type: application/json', true, 401); echo json_encode(['error' => 'Acesso restrito a admnistradores']); exit; } } + + public function validatesToken($token) { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + + if (!$key) { + return null; + } + + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; + } + } } diff --git a/app/Middleware/Authenticate.php b/app/Middleware/Authenticate.php index d56a757..bd2c831 100644 --- a/app/Middleware/Authenticate.php +++ b/app/Middleware/Authenticate.php @@ -5,16 +5,49 @@ use Core\Exceptions\HTTPException; use Core\Http\Middleware\Middleware; use Core\Http\Request; +use Exception; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; use Lib\Authentication\Auth; +use function dd; +use function glob; class Authenticate implements Middleware { - public function handle(Request $request): void - { - if (!Auth::check()) { - header('Content-Type: application/json', true, 401); - echo json_encode(['error' => 'Você precisa estar autenticado para acessar esta página.']); - exit; - } + public function handle(Request $request): void + { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + http_response_code(401); + echo json_encode(["error" => "Token não fornecido"]); + exit(); } + + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = $this->validatesToken($token); + + if (!$data) { + http_response_code(401); + echo json_encode(["error" => "Token inválido"]); + exit(); + } + +// echo json_encode(["message" => "Autorizado", "user" => $data]); + } + + public function validatesToken($token) { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + + if (!$key) { + return null; + } + + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; + } + } + } diff --git a/composer.json b/composer.json index e56b1d7..7818e4c 100644 --- a/composer.json +++ b/composer.json @@ -17,5 +17,8 @@ "phpunit/phpunit": "^11.1", "squizlabs/php_codesniffer": "*", "phpstan/phpstan": "^1.10" + }, + "require": { + "firebase/php-jwt": "^6.11" } } diff --git a/composer.lock b/composer.lock index 611309d..35c001a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,72 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1f3adee7b02b489d60204f84df44dd59", - "packages": [], + "content-hash": "67405feb9efac0986df93248e20cc662", + "packages": [ + { + "name": "firebase/php-jwt", + "version": "v6.11.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.11.0" + }, + "time": "2025-01-23T05:11:06+00:00" + } + ], "packages-dev": [ { "name": "myclabs/deep-copy", @@ -1784,5 +1848,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" } diff --git a/config/bootstrap.php b/config/bootstrap.php index 54829de..a8bd25a 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -4,13 +4,12 @@ header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization'); header('Access-Control-Allow-Credentials: true'); - +header('Access-Control-Max-Age: 86400'); if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { http_response_code(200); exit(); } - require __DIR__ . '/../vendor/autoload.php'; use Core\Env\EnvLoader; diff --git a/config/routes.php b/config/routes.php index 814ac75..00fbfc7 100644 --- a/config/routes.php +++ b/config/routes.php @@ -23,85 +23,83 @@ Route::get('/blocks', [BlockController::class, 'index']) ->name('blocks'); +Route::get('/classrooms', [ClassRoomController::class, 'index']) + ->name('classroom'); +Route::get('/classrooms/{id}', [ClassRoomController::class, 'show']) + ->name('classroom.show'); + Route::middleware('auth')->group(function () { - Route::get('/logout', [UsersController::class, 'destroy']) - ->name('users.logout'); - Route::get('/dashboard', [DashboardController::class, 'index']) - ->name('dashboard'); - Route::get('/users/professors', [UsersController::class, 'professors']) - ->name('users.professors'); - - - -// Route::middleware('role:admin')->group(function () { - Route::post('/blocks', [BlockController::class, 'create']) - ->name('blocks.create'); - Route::post('/blocks/image-update/{id}', [BlockController::class, 'imageUpdate']) - ->name('blocks.image'); - Route::put('/blocks/{id}', [BlockController::class, 'update']) - ->name('blocks.update'); - Route::delete('/blocks/{id}', [BlockController::class, 'destroy']) - ->name('blocks.destroy'); - - Route::post('/classrooms', [ClassRoomController::class, 'create']) - ->name('classroom.create'); - Route::put('/classrooms/{id}', [ClassRoomController::class, 'update']) - ->name('classroom.update'); - Route::delete('/classrooms/{id}', [ClassRoomController::class, 'destroy']) - ->name('classroom.destroy'); - - - Route::post('/subjects', [SubjectController::class, 'create']) - ->name('subject.create'); - Route::put('/subjects/{id}', [SubjectController::class, 'update']) - ->name('subject.update'); - Route::delete('/subjects/{id}', [SubjectController::class, 'destroy']) - ->name('subject.destroy'); - - Route::post('/user-subjects', [UserSubjectsController::class, 'addSubjectToProfessor']) - ->name('subject.professor.create'); - Route::delete('/user-subjects/{id}', [UserSubjectsController::class, 'delete']) - ->name('subject.professor.delete'); - - Route::post('/schedules', [SchedulesController::class, 'create']) - ->name('schedules.create'); - Route::delete('/schedules/{id}', [SchedulesController::class, 'delete']) - ->name('schedules.delete'); -// }); - - Route::get('/schedules', [SchedulesController::class, 'index']) - ->name('schedules.index'); - - Route::get('/schedules/professor/{id}', [SchedulesController::class, 'byProfessorId']) + Route::get('/user-subjects', [UserSubjectsController::class, 'index']) + ->name('subject.professor'); + + Route::get('/logout', [UsersController::class, 'destroy']) + ->name('users.logout'); + Route::get('/dashboard', [DashboardController::class, 'index']) + ->name('dashboard'); + Route::get('/users/professors', [UsersController::class, 'professors']) + ->name('users.professors'); + + Route::middleware('role:admin')->group(function () { + Route::post('/blocks', [BlockController::class, 'create']) + ->name('blocks.create'); + Route::post('/blocks/image-update/{id}', [BlockController::class, 'imageUpdate']) + ->name('blocks.image'); + Route::put('/blocks/{id}', [BlockController::class, 'update']) + ->name('blocks.update'); + Route::delete('/blocks/{id}', [BlockController::class, 'destroy']) + ->name('blocks.destroy'); + + Route::post('/classrooms', [ClassRoomController::class, 'create']) + ->name('classroom.create'); + Route::put('/classrooms/{id}', [ClassRoomController::class, 'update']) + ->name('classroom.update'); + Route::delete('/classrooms/{id}', [ClassRoomController::class, 'destroy']) + ->name('classroom.destroy'); + + Route::post('/subjects', [SubjectController::class, 'create']) + ->name('subject.create'); + Route::put('/subjects/{id}', [SubjectController::class, 'update']) + ->name('subject.update'); + Route::delete('/subjects/{id}', [SubjectController::class, 'destroy']) + ->name('subject.destroy'); + + Route::post('/user-subjects', [UserSubjectsController::class, 'addSubjectToProfessor']) + ->name('subject.professor.create'); + Route::delete('/user-subjects/{id}', [UserSubjectsController::class, 'delete']) + ->name('subject.professor.delete'); + + Route::post('/schedules', [SchedulesController::class, 'create']) + ->name('schedules.create'); + Route::delete('/schedules/{id}', [SchedulesController::class, 'delete']) + ->name('schedules.delete'); + }); + + // Outras rotas protegidas + Route::get('/schedules', [SchedulesController::class, 'index']) + ->name('schedules.index'); + + Route::get('/schedules/professor/{id}', [SchedulesController::class, 'byProfessorId']) ->name('schedules.userId'); - Route::get('/schedules/{id}', [SchedulesController::class, 'show']) - ->name('schedules.show'); - Route::post('/schedules/cancel', [SchedulesController::class, 'creatreCancelSchedule']) - ->name('schedules.cancel'); - Route::delete('/schedules/cancel/{id}', [SchedulesController::class, 'deleteCancelSchedule']) - ->name('schedules.cancel.delete'); - Route::post('/schedules/change', [SchedulesController::class, 'roomChange']) - ->name('schedules.post'); + Route::get('/schedules/{id}', [SchedulesController::class, 'show']) + ->name('schedules.show'); + Route::post('/schedules/cancel', [SchedulesController::class, 'creatreCancelSchedule']) + ->name('schedules.cancel'); + Route::delete('/schedules/cancel/{id}', [SchedulesController::class, 'deleteCancelSchedule']) + ->name('schedules.cancel.delete'); + Route::post('/schedules/change', [SchedulesController::class, 'roomChange']) + ->name('schedules.post'); - Route::get('/schedules/exceptions', [SchedulesController::class, 'exceptions']) + Route::get('/schedules/exceptions', [SchedulesController::class, 'exceptions']) ->name('schedules.exceptions'); + Route::get('/blocks/{id}', [BlockController::class, 'show']) + ->name('blocks.show'); - Route::get('/blocks/{id}', [BlockController::class, 'show']) - ->name('blocks.show'); - - Route::get('/classrooms', [ClassRoomController::class, 'index']) - ->name('classroom'); - Route::get('/classrooms/{id}', [ClassRoomController::class, 'show']) - ->name('classroom.show'); - - Route::get('/subjects', [SubjectController::class, 'index']) - ->name('subject'); - Route::get('/subjects/{id}', [SubjectController::class, 'show']) - ->name('subject.show'); - - Route::get('/user-subjects', [UserSubjectsController::class, 'index']) - ->name('subject.professor'); + Route::get('/subjects', [SubjectController::class, 'index']) + ->name('subject'); + Route::get('/subjects/{id}', [SubjectController::class, 'show']) + ->name('subject.show'); }); + diff --git a/lib/Authentication/Auth.php b/lib/Authentication/Auth.php index e435022..c624e0e 100644 --- a/lib/Authentication/Auth.php +++ b/lib/Authentication/Auth.php @@ -4,6 +4,14 @@ use App\Models\User; +use Exception; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; +use function dd; +use function getallheaders; +use function getenv; +use function http_response_code; +use function json_encode; use function str_replace; class Auth @@ -13,25 +21,43 @@ public static function login($user): void $_SESSION['user']['id'] = $user->id; } - public static function user(): ?User - { - if (isset($_SESSION['user']['id'])) { - $id = $_SESSION['user']['id']; - return User::findById($id); - } - return null; + public static function user(): ?User + { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { +// http_response_code(401); +// echo json_encode(["error" => "Token não fornecido"]); + return null; + exit(); + } + + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = self::validatesToken($token); // Alterado para 'self::' porque 'validatesToken' é estático + if (isset($data['user_id'])) { + return User::findById($data['user_id']); + } + return null; + } + + public static function validatesToken($token) + { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + + if (!$key) { + return null; + } + + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; } + } public static function check(): bool { - return true; - if ($_SESSION['user']['id'] == str_replace("Bearer ", "", $_SERVER["HTTP_AUTHORIZATION"])) { - return true; - } - return false; -// $token = str_replace("Bearer ", "", $_SERVER["HTTP_AUTHORIZATION"]); -// return $_SESSION['user']['id'] == $token; -// return isset($_SESSION['user']['id']) && self::user() !== null; + return self::user() !== null; } public static function logout(): void From bfb5e98679ecd4d0b993d1cd39236ad806199381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Abdala=20Bohaczk?= Date: Mon, 24 Feb 2025 21:51:06 -0300 Subject: [PATCH 2/2] lintes + test corrections --- app/Controllers/BlockController.php | 26 +++---- app/Controllers/ClassRoomController.php | 26 +++---- app/Controllers/SchedulesController.php | 24 +++--- app/Controllers/SubjectController.php | 26 +++---- app/Controllers/UsersController.php | 6 +- app/Middleware/AdminRole.php | 54 ++++++++------ app/Middleware/Authenticate.php | 73 ++++++++++--------- config/routes.php | 97 ++++++++++++------------- lib/Authentication/Auth.php | 58 +++++++-------- tests/Unit/Models/SchedulesTest.php | 2 +- 10 files changed, 202 insertions(+), 190 deletions(-) diff --git a/app/Controllers/BlockController.php b/app/Controllers/BlockController.php index df43894..c68cb71 100644 --- a/app/Controllers/BlockController.php +++ b/app/Controllers/BlockController.php @@ -5,8 +5,8 @@ use App\Models\Block; use Core\Http\Controllers\Controller; use Core\Http\Request; - use Exception; + use function array_map; use function is_null; use function json_encode; @@ -111,20 +111,20 @@ public function imageUpdate(Request $request): void public function destroy(Request $request): void { - try { - $params = $request->getParams(); - $block = Block::findById($params['id']); + try { + $params = $request->getParams(); + $block = Block::findById($params['id']); - if (!$block) { - echo json_encode(['error' => 'Bloco não encontrado']); - return; - } + if (!$block) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } - $block->destroy(); + $block->destroy(); - echo json_encode(['success' => 'Deletado com sucesso']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - } + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/ClassRoomController.php b/app/Controllers/ClassRoomController.php index 1ebe5a5..30b8758 100644 --- a/app/Controllers/ClassRoomController.php +++ b/app/Controllers/ClassRoomController.php @@ -10,8 +10,8 @@ use Core\Http\Request; use Exception; use PDO; - use PDOException; + use function is_null; use function json_encode; @@ -90,20 +90,20 @@ public function update(Request $request): void public function destroy(Request $request): void { - try { - $params = $request->getParams(); - $classroom = ClassRoom::findById($params['id']); + try { + $params = $request->getParams(); + $classroom = ClassRoom::findById($params['id']); - if (!$classroom) { - echo json_encode(['error' => 'Bloco não encontrado']); - return; - } + if (!$classroom) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } - $classroom->destroy(); + $classroom->destroy(); - echo json_encode(['success' => 'Deletado com sucesso']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - } + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/SchedulesController.php b/app/Controllers/SchedulesController.php index 8058adc..50538b1 100644 --- a/app/Controllers/SchedulesController.php +++ b/app/Controllers/SchedulesController.php @@ -259,21 +259,21 @@ public function roomChange(Request $request): void public function delete(Request $request): void { - try { - $params = $request->getParams(); - $schedule = Schedules::findById($params['id']); + try { + $params = $request->getParams(); + $schedule = Schedules::findById($params['id']); - if (!$schedule) { - echo json_encode(['error' => 'Bloco não encontrado']); - return; - } + if (!$schedule) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } - $schedule->destroy(); + $schedule->destroy(); - echo json_encode(['success' => 'Deletado com sucesso']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - } + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } public function validatesDateConflict(Schedules $schedule): bool diff --git a/app/Controllers/SubjectController.php b/app/Controllers/SubjectController.php index 698f4b1..0c9ddaf 100644 --- a/app/Controllers/SubjectController.php +++ b/app/Controllers/SubjectController.php @@ -6,8 +6,8 @@ use App\Models\Subject; use Core\Http\Controllers\Controller; use Core\Http\Request; - use Exception; + use function array_map; use function is_null; use function json_encode; @@ -86,20 +86,20 @@ public function update(Request $request): void public function destroy(Request $request): void { - try { - $params = $request->getParams(); - $subject = Subject::findById($params['id']); + try { + $params = $request->getParams(); + $subject = Subject::findById($params['id']); - if (!$subject) { - echo json_encode(['error' => 'Bloco não encontrado']); - return; - } + if (!$subject) { + echo json_encode(['error' => 'Bloco não encontrado']); + return; + } - $subject->destroy(); + $subject->destroy(); - echo json_encode(['success' => 'Deletado com sucesso']); - } catch (Exception $e) { - echo json_encode(['error' => $e->getMessage()]); - } + echo json_encode(['success' => 'Deletado com sucesso']); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + } } } diff --git a/app/Controllers/UsersController.php b/app/Controllers/UsersController.php index 6864773..2cfd6e7 100644 --- a/app/Controllers/UsersController.php +++ b/app/Controllers/UsersController.php @@ -41,14 +41,14 @@ public function login(Request $request): void if ($user && $user->authenticate($params['password'])) { Auth::login($user); - $payload = [ + $payload = [ "iss" => "http://localhost", "aud" => "http://localhost", "iat" => time(), "exp" => time() + (60 * 60), "user_id" => $user->id - ]; - $token = JWT::encode($payload,$_ENV['PASSWORD_KEY_HASH'], 'HS256'); + ]; + $token = JWT::encode($payload, $_ENV['PASSWORD_KEY_HASH'], 'HS256'); echo json_encode([ 'success' => 'Logado com sucesso', 'role' => $user->roleName(), diff --git a/app/Middleware/AdminRole.php b/app/Middleware/AdminRole.php index df98b8a..d4133e0 100644 --- a/app/Middleware/AdminRole.php +++ b/app/Middleware/AdminRole.php @@ -10,6 +10,7 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; use Lib\Authentication\Auth; + use function dd; use function getenv; use function http_response_code; @@ -20,36 +21,43 @@ class AdminRole implements Middleware { public function handle(Request $request): void { - $headers = getallheaders(); - if (!isset($headers['Authorization'])) { - http_response_code(401); - echo json_encode(["error" => "Token não fornecido"]); - exit(); - } - - $token = str_replace('Bearer ', '', $headers['Authorization']); - $data = $this->validatesToken($token); - $user = User::findById($data['user_id']); - - if ($user->role_id != 1) { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + http_response_code(401); + echo json_encode(["error" => "Token não fornecido"]); + exit(); + } + + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = $this->validatesToken($token); + $user = User::findById($data['user_id']); + + if ($user->role_id != 1) { header('Content-Type: application/json', true, 401); echo json_encode(['error' => 'Acesso restrito a admnistradores']); exit; } } - public function validatesToken($token) { - $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + /** + * + * @param string $token + * @return array|null + */ - if (!$key) { - return null; - } + public function validatesToken(string $token): ?array + { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + + if (!$key) { + return null; + } - try { - $decoded = JWT::decode($token, new Key($key, 'HS256')); - return (array) $decoded; - } catch (Exception $e) { - return null; + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; + } } - } } diff --git a/app/Middleware/Authenticate.php b/app/Middleware/Authenticate.php index bd2c831..cf24da1 100644 --- a/app/Middleware/Authenticate.php +++ b/app/Middleware/Authenticate.php @@ -9,45 +9,50 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; use Lib\Authentication\Auth; + use function dd; use function glob; class Authenticate implements Middleware { - public function handle(Request $request): void - { - $headers = getallheaders(); - if (!isset($headers['Authorization'])) { - http_response_code(401); - echo json_encode(["error" => "Token não fornecido"]); - exit(); - } - - $token = str_replace('Bearer ', '', $headers['Authorization']); - $data = $this->validatesToken($token); - - if (!$data) { - http_response_code(401); - echo json_encode(["error" => "Token inválido"]); - exit(); - } - -// echo json_encode(["message" => "Autorizado", "user" => $data]); - } - - public function validatesToken($token) { - $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); - - if (!$key) { - return null; + public function handle(Request $request): void + { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + http_response_code(401); + echo json_encode(["error" => "Token não fornecido"]); + exit(); + } + + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = $this->validatesToken($token); + + if (!$data) { + http_response_code(401); + echo json_encode(["error" => "Token inválido"]); + exit(); + } + + // echo json_encode(["message" => "Autorizado", "user" => $data]); } - - try { - $decoded = JWT::decode($token, new Key($key, 'HS256')); - return (array) $decoded; - } catch (Exception $e) { - return null; + /** + * + * @param string $token + * @return array|null + */ + public function validatesToken(string $token): ?array + { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + + if (!$key) { + return null; + } + + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; + } } - } - } diff --git a/config/routes.php b/config/routes.php index 00fbfc7..74de9b4 100644 --- a/config/routes.php +++ b/config/routes.php @@ -30,76 +30,75 @@ Route::middleware('auth')->group(function () { - Route::get('/user-subjects', [UserSubjectsController::class, 'index']) + Route::get('/user-subjects', [UserSubjectsController::class, 'index']) ->name('subject.professor'); - Route::get('/logout', [UsersController::class, 'destroy']) + Route::get('/logout', [UsersController::class, 'destroy']) ->name('users.logout'); - Route::get('/dashboard', [DashboardController::class, 'index']) + Route::get('/dashboard', [DashboardController::class, 'index']) ->name('dashboard'); - Route::get('/users/professors', [UsersController::class, 'professors']) + Route::get('/users/professors', [UsersController::class, 'professors']) ->name('users.professors'); - Route::middleware('role:admin')->group(function () { - Route::post('/blocks', [BlockController::class, 'create']) - ->name('blocks.create'); - Route::post('/blocks/image-update/{id}', [BlockController::class, 'imageUpdate']) - ->name('blocks.image'); - Route::put('/blocks/{id}', [BlockController::class, 'update']) - ->name('blocks.update'); - Route::delete('/blocks/{id}', [BlockController::class, 'destroy']) - ->name('blocks.destroy'); - - Route::post('/classrooms', [ClassRoomController::class, 'create']) - ->name('classroom.create'); - Route::put('/classrooms/{id}', [ClassRoomController::class, 'update']) - ->name('classroom.update'); - Route::delete('/classrooms/{id}', [ClassRoomController::class, 'destroy']) - ->name('classroom.destroy'); - - Route::post('/subjects', [SubjectController::class, 'create']) - ->name('subject.create'); - Route::put('/subjects/{id}', [SubjectController::class, 'update']) - ->name('subject.update'); - Route::delete('/subjects/{id}', [SubjectController::class, 'destroy']) - ->name('subject.destroy'); - - Route::post('/user-subjects', [UserSubjectsController::class, 'addSubjectToProfessor']) - ->name('subject.professor.create'); - Route::delete('/user-subjects/{id}', [UserSubjectsController::class, 'delete']) - ->name('subject.professor.delete'); - - Route::post('/schedules', [SchedulesController::class, 'create']) - ->name('schedules.create'); - Route::delete('/schedules/{id}', [SchedulesController::class, 'delete']) - ->name('schedules.delete'); - }); + Route::middleware('role:admin')->group(function () { + Route::post('/blocks', [BlockController::class, 'create']) + ->name('blocks.create'); + Route::post('/blocks/image-update/{id}', [BlockController::class, 'imageUpdate']) + ->name('blocks.image'); + Route::put('/blocks/{id}', [BlockController::class, 'update']) + ->name('blocks.update'); + Route::delete('/blocks/{id}', [BlockController::class, 'destroy']) + ->name('blocks.destroy'); + + Route::post('/classrooms', [ClassRoomController::class, 'create']) + ->name('classroom.create'); + Route::put('/classrooms/{id}', [ClassRoomController::class, 'update']) + ->name('classroom.update'); + Route::delete('/classrooms/{id}', [ClassRoomController::class, 'destroy']) + ->name('classroom.destroy'); + + Route::post('/subjects', [SubjectController::class, 'create']) + ->name('subject.create'); + Route::put('/subjects/{id}', [SubjectController::class, 'update']) + ->name('subject.update'); + Route::delete('/subjects/{id}', [SubjectController::class, 'destroy']) + ->name('subject.destroy'); + + Route::post('/user-subjects', [UserSubjectsController::class, 'addSubjectToProfessor']) + ->name('subject.professor.create'); + Route::delete('/user-subjects/{id}', [UserSubjectsController::class, 'delete']) + ->name('subject.professor.delete'); + + Route::post('/schedules', [SchedulesController::class, 'create']) + ->name('schedules.create'); + Route::delete('/schedules/{id}', [SchedulesController::class, 'delete']) + ->name('schedules.delete'); + }); // Outras rotas protegidas - Route::get('/schedules', [SchedulesController::class, 'index']) + Route::get('/schedules', [SchedulesController::class, 'index']) ->name('schedules.index'); - Route::get('/schedules/professor/{id}', [SchedulesController::class, 'byProfessorId']) + Route::get('/schedules/professor/{id}', [SchedulesController::class, 'byProfessorId']) ->name('schedules.userId'); - Route::get('/schedules/{id}', [SchedulesController::class, 'show']) + Route::get('/schedules/{id}', [SchedulesController::class, 'show']) ->name('schedules.show'); - Route::post('/schedules/cancel', [SchedulesController::class, 'creatreCancelSchedule']) + Route::post('/schedules/cancel', [SchedulesController::class, 'creatreCancelSchedule']) ->name('schedules.cancel'); - Route::delete('/schedules/cancel/{id}', [SchedulesController::class, 'deleteCancelSchedule']) + Route::delete('/schedules/cancel/{id}', [SchedulesController::class, 'deleteCancelSchedule']) ->name('schedules.cancel.delete'); - Route::post('/schedules/change', [SchedulesController::class, 'roomChange']) + Route::post('/schedules/change', [SchedulesController::class, 'roomChange']) ->name('schedules.post'); - Route::get('/schedules/exceptions', [SchedulesController::class, 'exceptions']) + Route::get('/schedules/exceptions', [SchedulesController::class, 'exceptions']) ->name('schedules.exceptions'); - Route::get('/blocks/{id}', [BlockController::class, 'show']) + Route::get('/blocks/{id}', [BlockController::class, 'show']) ->name('blocks.show'); - Route::get('/subjects', [SubjectController::class, 'index']) + Route::get('/subjects', [SubjectController::class, 'index']) ->name('subject'); - Route::get('/subjects/{id}', [SubjectController::class, 'show']) + Route::get('/subjects/{id}', [SubjectController::class, 'show']) ->name('subject.show'); }); - diff --git a/lib/Authentication/Auth.php b/lib/Authentication/Auth.php index c624e0e..6d2850f 100644 --- a/lib/Authentication/Auth.php +++ b/lib/Authentication/Auth.php @@ -3,10 +3,10 @@ namespace Lib\Authentication; use App\Models\User; - use Exception; use Firebase\JWT\JWT; use Firebase\JWT\Key; + use function dd; use function getallheaders; use function getenv; @@ -21,43 +21,43 @@ public static function login($user): void $_SESSION['user']['id'] = $user->id; } - public static function user(): ?User - { - $headers = getallheaders(); - if (!isset($headers['Authorization'])) { -// http_response_code(401); -// echo json_encode(["error" => "Token não fornecido"]); - return null; - exit(); - } + public static function user(): ?User + { + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + // http_response_code(401); + // echo json_encode(["error" => "Token não fornecido"]); + return null; + exit(); + } - $token = str_replace('Bearer ', '', $headers['Authorization']); - $data = self::validatesToken($token); // Alterado para 'self::' porque 'validatesToken' é estático - if (isset($data['user_id'])) { - return User::findById($data['user_id']); + $token = str_replace('Bearer ', '', $headers['Authorization']); + $data = self::validatesToken($token); // Alterado para 'self::' porque 'validatesToken' é estático + if (isset($data['user_id'])) { + return User::findById($data['user_id']); + } + return null; } - return null; - } - public static function validatesToken($token) - { - $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); + public static function validatesToken($token) + { + $key = $_ENV['PASSWORD_KEY_HASH'] ?? getenv('PASSWORD_KEY_HASH'); - if (!$key) { - return null; - } + if (!$key) { + return null; + } - try { - $decoded = JWT::decode($token, new Key($key, 'HS256')); - return (array) $decoded; - } catch (Exception $e) { - return null; + try { + $decoded = JWT::decode($token, new Key($key, 'HS256')); + return (array) $decoded; + } catch (Exception $e) { + return null; + } } - } public static function check(): bool { - return self::user() !== null; + return self::user() !== null; } public static function logout(): void diff --git a/tests/Unit/Models/SchedulesTest.php b/tests/Unit/Models/SchedulesTest.php index a3fa883..5be6788 100644 --- a/tests/Unit/Models/SchedulesTest.php +++ b/tests/Unit/Models/SchedulesTest.php @@ -226,7 +226,6 @@ public function setUp(): void public function test_should_create_new_schedules(): void { - dd('Schedules::all()'); $this->assertCount(9, Schedules::all()); } @@ -257,6 +256,7 @@ public function teste_should_change_room(): void 'is_canceled' => 0, 'date' => $this->date, 'exceptional_day' => 1, + 'block_id' => $schedule->block_id ]); $changeSchedule->save(); $schedules = Schedules::withCancelAndSubstitutionsCurrentWeek($this->date);