Skip to main content

Descripción General

El sistema utiliza Laravel Sanctum para autenticación basada en tokens. Los usuarios pueden autenticarse con email o nombre de usuario, y reciben un token JWT válido por 8 horas.

Flujo de Autenticación

1

Usuario envía credenciales

El cliente envía user (email o username) y password al endpoint /api/login.
2

Validación de credenciales

El servidor verifica:
  • Usuario existe en la base de datos
  • Contraseña coincide (bcrypt)
  • Usuario no está deshabilitado
3

Generación de token

Si las credenciales son válidas:
  • Se inicia sesión de Laravel (para exportaciones vía web)
  • Se genera token Sanctum válido por 8 horas
  • Se cargan empresas y permisos del usuario
4

Respuesta al cliente

El servidor responde con:
  • Token de acceso
  • Datos del usuario
  • Empresas disponibles
  • Permisos asignados
5

Uso del token

El cliente almacena el token y lo incluye en todas las peticiones:
Authorization: Bearer {token}

Modelo de Usuario

Tabla users

CREATE TABLE users (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,              -- Nombre de usuario (login)
  email VARCHAR(255) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,          -- Hash bcrypt
  rol_id INT NOT NULL,                     -- FK a roles
  id_empresa INT NOT NULL,                 -- FK a empresas
  num_doc VARCHAR(20),                     -- DNI/RUC
  nombres VARCHAR(255),
  apellidos VARCHAR(255),
  telefono VARCHAR(20),
  estado BOOLEAN DEFAULT 1,
  foto_perfil VARCHAR(255),
  email_verified_at TIMESTAMP NULL,
  remember_token VARCHAR(100),
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  
  FOREIGN KEY (rol_id) REFERENCES roles(rol_id),
  FOREIGN KEY (id_empresa) REFERENCES empresas(id_empresa)
);

Relaciones del Modelo

app/Models/User.php
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    protected $fillable = [
        'name', 'email', 'password', 'rol_id', 'id_empresa',
        'num_doc', 'nombres', 'apellidos', 'telefono', 'estado', 'foto_perfil',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    public function empresa()
    {
        return $this->belongsTo(Empresa::class, 'id_empresa', 'id_empresa');
    }

    public function rol()
    {
        return $this->belongsTo(Rol::class, 'rol_id', 'rol_id');
    }
}

Login Flexible

El sistema acepta email o nombre de usuario en el campo user:
app/Http/Controllers/Api/AuthController.php:26
// Buscar usuario por email o name
$user = User::where('email', $request->user)
    ->orWhere('name', $request->user)
    ->first();
Esto permite a los usuarios ingresar con:

Sesión Dual: Token + Session

El sistema mantiene dos tipos de sesión:

1. Token Sanctum (API)

Usado para peticiones AJAX desde el frontend:
app/Http/Controllers/Api/AuthController.php:49
// Generar token con Sanctum (válido por 8 horas)
$token = $user->createToken('auth_token', ['*'], now()->addHours(8))->plainTextToken;

2. Sesión Laravel (Web)

Usada para rutas web como exportaciones de PDF:
app/Http/Controllers/Api/AuthController.php:46
// Iniciar sesión de Laravel (para exportaciones vía web)
\Illuminate\Support\Facades\Auth::login($user);
Esto permite que las descargas de PDF (que abren en nueva pestaña) funcionen sin pasar el token por URL.

Carga de Datos en Login

Empresas Disponibles

app/Http/Controllers/Api/AuthController.php:52
$empresas = [];
if ($user->rol_id == 1) {
    // Admin: todas las empresas
    $empresas = \App\Models\Empresa::where('estado', '1')
        ->select('id_empresa', 'comercial', 'ruc', 'razon_social', 'logo', 'direccion')
        ->get();
} elseif ($user->id_empresa) {
    // Usuario normal: solo su empresa
    $empresa = \App\Models\Empresa::where('id_empresa', $user->id_empresa)
        ->select('id_empresa', 'comercial', 'ruc', 'razon_social', 'logo', 'direccion')
        ->first();
    if ($empresa) {
        $empresas = [$empresa];
    }
}

Permisos del Usuario

app/Http/Controllers/Api/AuthController.php:68
$permissions = [];
if ($user->rol_id == 1) {
    // Admin tiene todos los permisos automáticamente
    $permissions = \App\Models\Permission::pluck('name')->toArray();
} elseif ($user->rol) {
    // Otros roles: solo sus permisos asignados
    $permissions = $user->rol->permissions->pluck('name')->toArray();
}

Gestión de Usuarios

Listar Usuarios

GET /api/users
curl -X GET "https://tu-dominio.com/api/users" \
  -H "Authorization: Bearer {token}"

Crear Usuario

POST /api/users
name
string
required
Nombre de usuario para login
email
string
required
Email único del usuario
password
string
required
Contraseña (mínimo 6 caracteres)
password_confirmation
string
required
Confirmación de contraseña
rol_id
integer
required
ID del rol asignado
id_empresa
integer
required
ID de la empresa
curl -X POST "https://tu-dominio.com/api/users" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "cajero1",
    "email": "[email protected]",
    "password": "password123",
    "password_confirmation": "password123",
    "rol_id": 3,
    "id_empresa": 1
  }'

Actualizar Usuario

PUT /api/users/{id}
Todos los campos son opcionales. Solo se actualizan los campos enviados.
curl -X PUT "https://tu-dominio.com/api/users/5" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "rol_id": 4
  }'

Eliminar Usuario

DELETE /api/users/{id}
No se puede eliminar el propio usuario autenticado.
curl -X DELETE "https://tu-dominio.com/api/users/5" \
  -H "Authorization: Bearer {token}"

Obtener Roles Disponibles

GET /api/users/roles
curl -X GET "https://tu-dominio.com/api/users/roles" \
  -H "Authorization: Bearer {token}"

Validaciones

Reglas de Validación

CampoReglaDescripción
namerequired, string, max:255Nombre de usuario
emailrequired, email, unique:usersEmail único
passwordrequired, min:6, confirmedContraseña con confirmación
rol_idrequired, exists:roles,rol_idRol válido
id_empresarequired, exists:empresas,id_empresaEmpresa válida

Mensajes de Error

Validación fallida
{
  "success": false,
  "message": "Error de validación",
  "errors": {
    "email": [
      "El email ya está en uso"
    ],
    "password": [
      "La contraseña debe tener al menos 6 caracteres",
      "Las contraseñas no coinciden"
    ]
  }
}

Seguridad

Hash de Contraseñas

Las contraseñas se almacenan con bcrypt:
$user->password = Hash::make($request->password);

Verificación de Contraseña

app/Http/Controllers/Api/AuthController.php:38
if (!Hash::check($request->password, $user->password)) {
    return response()->json([
        'success' => false,
        'message' => 'Contraseña incorrecta'
    ], 401);
}

Tokens Sanctum

  • Duración: 8 horas por defecto
  • Scopes: ['*'] (todos los permisos)
  • Revocación: Se elimina al hacer logout

Middleware de Autenticación

routes/api.php:24
Route::middleware(['token.query', 'auth:sanctum'])->group(function () {
    // Rutas protegidas
});
El middleware token.query permite pasar el token como query parameter para PDFs:
/reporteNV/{id}?token={token}

Mejores Prácticas

Contraseñas Seguras

Requiere contraseñas de al menos 8 caracteres con mayúsculas, minúsculas y números.

Renovación de Tokens

Implementa refresh automático antes de que expire el token de 8 horas.

Auditoría de Accesos

Registra intentos de login fallidos y accesos exitosos.

Validación de Email

Implementa verificación de email para nuevos usuarios.

Códigos de Error

CódigoMensajeCausa
401Usuario no encontradoEl usuario no existe
401Contraseña incorrectaContraseña no coincide
401No autenticadoToken inválido o expirado
403No puedes eliminar tu propia cuentaIntento de auto-eliminación
404Usuario no encontradoID de usuario inválido
422Error de validaciónDatos inválidos
500Error al crear usuarioError de base de datos

Build docs developers (and LLMs) love