jwt endpoint arcos

This commit is contained in:
Juan Felipe Zapata Moreno 2026-01-06 17:03:01 -06:00
parent 2daa9ee98f
commit aac383fc83
10 changed files with 127 additions and 16 deletions

View File

@ -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
]);
}

View File

@ -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
);

View File

@ -0,0 +1,45 @@
<?php
namespace App\Http\Middleware;
use App\Models\Arco;
use Closure;
use Illuminate\Http\Request;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use Symfony\Component\HttpFoundation\Response;
class ArcoTokenMiddleware
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): Response
{
$token = $request->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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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');

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('arcos', function (Blueprint $table) {
$table->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');
});
}
};

View File

@ -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']);