From aac383fc83419c8d395539c3ab5ae7f2d4662628 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Tue, 6 Jan 2026 17:03:01 -0600 Subject: [PATCH] jwt endpoint arcos --- app/Http/Controllers/Api/ArcoController.php | 3 +- .../Controllers/Api/VehicleController.php | 7 ++- app/Http/Middleware/ArcoTokenMiddleware.php | 45 +++++++++++++++++++ app/Models/Arco.php | 34 ++++++++++++++ app/Services/ConsultaRepuveConstancia.php | 1 - app/Services/VehicleService.php | 12 ++--- bootstrap/app.php | 1 + .../2026_01_06_113001_create_arcos_table.php | 2 +- ...06_155208_add_api_token_to_arcos_table.php | 30 +++++++++++++ routes/api.php | 8 +++- 10 files changed, 127 insertions(+), 16 deletions(-) create mode 100644 app/Http/Middleware/ArcoTokenMiddleware.php create mode 100644 database/migrations/2026_01_06_155208_add_api_token_to_arcos_table.php diff --git a/app/Http/Controllers/Api/ArcoController.php b/app/Http/Controllers/Api/ArcoController.php index c80f8ee..5c766dc 100644 --- a/app/Http/Controllers/Api/ArcoController.php +++ b/app/Http/Controllers/Api/ArcoController.php @@ -55,7 +55,8 @@ public function store(Request $request) return ApiResponse::CREATED->response([ 'message' => 'Arco creado exitosamente', - 'arco' => $arco + 'arco' => $arco, + 'api_token' => $arco->api_token ]); } diff --git a/app/Http/Controllers/Api/VehicleController.php b/app/Http/Controllers/Api/VehicleController.php index c67405d..1c3aa3b 100644 --- a/app/Http/Controllers/Api/VehicleController.php +++ b/app/Http/Controllers/Api/VehicleController.php @@ -379,23 +379,26 @@ public function buscarVehiculoRobado(Request $request) /** * Procesar detección de tag RFID * POST /api/vehicles/buscar + * Requiere autenticación mediante token de arco */ public function buscarPorTag(Request $request) { $validated = $request->validate([ 'fast_id' => 'required|string', 'epc' => 'nullable|string', - 'arco_ip' => 'nullable|ip', 'timestamp' => 'nullable|date' ]); + // Obtener el arco autenticado del middleware + $arco = $request->get('arco_autenticado'); + // Si no se proporciona EPC, usar el FastID como identificador $epc = $validated['epc'] ?? $validated['fast_id']; $resultado = $this->vehicleService->procesarDeteccion( $epc, $validated['fast_id'], - $validated['arco_ip'], + $arco->ip_address, $validated['timestamp'] ?? null ); diff --git a/app/Http/Middleware/ArcoTokenMiddleware.php b/app/Http/Middleware/ArcoTokenMiddleware.php new file mode 100644 index 0000000..c128b69 --- /dev/null +++ b/app/Http/Middleware/ArcoTokenMiddleware.php @@ -0,0 +1,45 @@ +bearerToken(); + + if (!$token) { + return ApiResponse::UNAUTHORIZED->response([ + 'message' => 'Token de arco no proporcionado' + ]); + } + + $arco = Arco::buscarPorToken($token); + + if (!$arco) { + return ApiResponse::UNAUTHORIZED->response([ + 'message' => 'Token de arco inválido' + ]); + } + + if (!$arco->activo) { + return ApiResponse::FORBIDDEN->response([ + 'message' => 'Arco desactivado' + ]); + } + + // Agregar el arco al request para uso posterior + $request->merge(['arco_autenticado' => $arco]); + + return $next($request); + } +} diff --git a/app/Models/Arco.php b/app/Models/Arco.php index f5305eb..0e7857a 100644 --- a/app/Models/Arco.php +++ b/app/Models/Arco.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Support\Str; /** * Modelo Arco RFID @@ -33,6 +34,21 @@ class Arco extends Model 'updated_at' => 'datetime' ]; + protected $hidden = [ + 'api_token' + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($arco) { + if (!$arco->api_token) { + $arco->api_token = Str::random(64); + } + }); + } + /** * Relación con detecciones */ @@ -56,4 +72,22 @@ public static function buscarPorIp(string $ip): ?self { return self::where('ip_address', $ip)->first(); } + + /** + * Buscar arco por API token + */ + public static function buscarPorToken(string $token): ?self + { + return self::where('api_token', $token)->first(); + } + + /** + * Regenerar API token + */ + public function regenerarToken(): string + { + $this->api_token = Str::random(64); + $this->save(); + return $this->api_token; + } } diff --git a/app/Services/ConsultaRepuveConstancia.php b/app/Services/ConsultaRepuveConstancia.php index 65868f1..da97cff 100644 --- a/app/Services/ConsultaRepuveConstancia.php +++ b/app/Services/ConsultaRepuveConstancia.php @@ -114,7 +114,6 @@ private function obtenerToken() // Intentar obtener token de caché $token = Cache::get($cacheKey); if ($token) { - Log::debug('ConsultaRepuveConstancia: Token obtenido de caché'); return $token; } diff --git a/app/Services/VehicleService.php b/app/Services/VehicleService.php index ad71698..e16bdb6 100644 --- a/app/Services/VehicleService.php +++ b/app/Services/VehicleService.php @@ -19,15 +19,9 @@ public function procesarDeteccion(string $epc, string $fastId, string $arcoIp, ? { $key = "vehiculo:robado:{$epc}"; - // Buscar o crear arco por IP - $arco = Arco::firstOrCreate( - ['ip_address' => $arcoIp], - [ - 'nombre' => 'Arco ' . $arcoIp, - 'activo' => true - ] - ); - $arcoId = $arco->id; + // Buscar arco por IP + $arco = Arco::buscarPorIp($arcoIp); + $arcoId = $arco?->id; // Verificar si está en Redis $enRedis = Redis::get($key); diff --git a/bootstrap/app.php b/bootstrap/app.php index d91dc64..17eece1 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -36,6 +36,7 @@ 'role' => \Spatie\Permission\Middleware\RoleMiddleware::class, 'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class, 'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class, + 'arco.token' => \App\Http\Middleware\ArcoTokenMiddleware::class, ]); }) ->withExceptions(function (Exceptions $exceptions) { diff --git a/database/migrations/2026_01_06_113001_create_arcos_table.php b/database/migrations/2026_01_06_113001_create_arcos_table.php index cdaab82..01a16fe 100644 --- a/database/migrations/2026_01_06_113001_create_arcos_table.php +++ b/database/migrations/2026_01_06_113001_create_arcos_table.php @@ -16,7 +16,7 @@ public function up(): void $table->string('nombre'); $table->string('ip_address')->unique(); $table->string('ubicacion')->nullable(); - $table->boolean('activo'); + $table->boolean('activo')->default(true); $table->timestamps(); $table->index('ip_address'); diff --git a/database/migrations/2026_01_06_155208_add_api_token_to_arcos_table.php b/database/migrations/2026_01_06_155208_add_api_token_to_arcos_table.php new file mode 100644 index 0000000..8bf2462 --- /dev/null +++ b/database/migrations/2026_01_06_155208_add_api_token_to_arcos_table.php @@ -0,0 +1,30 @@ +string('api_token', 64)->unique()->nullable()->after('activo'); + $table->index('api_token'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('arcos', function (Blueprint $table) { + $table->dropIndex(['api_token']); + $table->dropColumn('api_token'); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 805036a..9b6b31b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -18,13 +18,17 @@ * Procura revisar que no existan rutas que entren en conflicto con las rutas del núcleo. */ -/** Rutas protegidas (requieren autenticación) */ +/** Rutas con autenticación de arco (token único por arco) */ +Route::middleware('arco.token')->group(function() { + Route::post('/vehicles/buscar', [VehicleController::class, 'buscarPorTag']); +}); + +/** Rutas protegidas (requieren autenticación JWT de usuario) */ Route::middleware('auth:api')->group(function() { // Rutas de Vehículos Route::post('/vehicles/consultar', [VehicleController::class, 'consultarVehiculo']); Route::post('/vehicles/recuperar', [VehicleController::class, 'recuperarVehiculo']); - Route::post('/vehicles/buscar', [VehicleController::class, 'buscarPorTag']); Route::get('/vehicles/detectar', [VehicleController::class, 'buscarVehiculo']); Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']); Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']);