Sistema de Autenticación y Permisos en Ragnos

Ragnos incorpora un sistema de autenticación ligero y flexible integrado directamente en el núcleo del framework. Este sistema gestiona sesiones de usuario, protección de controladores y control de acceso basado en roles (grupos).

El sistema se apoya principalmente en el servicio App\Services\Admin_aut y en la clase BaseController.

Tablas de Base de Datos

El sistema espera una estructura de base de datos específica:

  • gen_usuarios: Tabla de usuarios (usu_id, usu_nombre, usu_login, usu_pword, usu_activo, usu_grupo).
  • gen_gruposdeusuarios: Tabla de roles (gru_id, gru_nombre).

Protección de Controladores

Todos los controladores que extienden de BaseController (incluyendo RDatasetController, RProcessController, etc.) tienen acceso a métodos de protección simplificados.

Flujo de Verificación

graph TD Req["Petición Entrante"] --> Controller["Controlador"] Controller -->|Llama| Check{"checkLogin( )"} Check -- "No hay sesión" --> Type{"¿Es API?"} Type -- "Sí" --> Error401["JSON 401 Unauthorized"] Type -- "No" --> Login["Redirigir a Login"] Check -- "Hay sesión" --> Group{"¿checkUserInGroup( )?"} Group -- "No requerido" --> Access["✅ Acceso Permitido"] Group -- "Requerido" --> Role{"¿Usuario en Grupo?"} Role -- "Sí" --> Access Role -- "No" --> Error403["⛔ Redirigir / Error 403"] %% Estilos mejorados style Access fill:#d4edda,stroke:#155724,stroke-width:2px,color:#155724 style Error401 fill:#f8d7da,stroke:#721c24,stroke-width:2px,color:#721c24 style Login fill:#fff3cd,stroke:#856404,stroke-width:2px,color:#856404 style Error403 fill:#f8d7da,stroke:#721c24,stroke-width:2px,color:#721c24

checkLogin()

Este método verifica si el usuario tiene una sesión activa. Si no la tiene:

  1. Para peticiones Web: Redirige al login (admin/login).
  2. Para API: Verifica el header Authorization contra el usu_token en base de datos. Si falla, devuelve un error 401 JSON.

Uso: Se recomienda llamarlo al inicio de cualquier función que requiera autenticación, o en el constructor si todo el controlador es privado.

Controllers Públicos

Si tienes un controlador público (ej. página de inicio), simplemente no llames a checkLogin().

public function miFunciopPrivada()
{
    $this->checkLogin();

    // El resto del código solo se ejecuta si el usuario está logueado
    return view('mi_vista');
}

checkUserInGroup($grupos)

Restringe el acceso exclusivamente a usuarios que pertenezcan a los grupos especificados.

  • Parámetro: Puede ser un string con el nombre de un grupo o un array de strings para permitir múltiples grupos.
  • Comportamiento:
  • Si no cumple la condición, redirige a admin/index (o devuelve 403/401 si es API).
  • Internamente llama a checkLogin(), por lo que no es necesario llamar a ambos.

Uso:

public function __construct()
{
    // Solo permitir acceso a Administradores
    $this->checkUserInGroup('Administrador');
}

public function reporteGerencial()
{
    // Permitir acceso a Administradores o Gerentes
    $this->checkUserInGroup(['Administrador', 'Gerencia']);

    // Lógica del reporte...
}

Servicio Admin_aut

Para lógica más granular dentro de tus vistas o controladores, puedes acceder directamente al servicio de autenticación.

Lo ideal es invocarlo mediante service('Admin_aut').

Funciones Principales

isLoggedIn()

Devuelve true si hay un usuario logueado, false en caso contrario.

if (service('Admin_aut')->isLoggedIn()) {
    echo "Usuario conectado";
}

id()

Devuelve el ID (usu_id) del usuario actual.

name()

Devuelve el nombre completo (usu_nombre) del usuario actual.

isUserInGroup($grupo)

Evalúa si el usuario actual pertenece al grupo indicado. Es muy útil para ocultar o mostrar botones en las vistas o aplicar lógica condicional. Comparación case-insensitive.

// En un controlador o vista
if (service('Admin_aut')->isUserInGroup('Ventas')) {
    // Mostrar botón de crear pedido
}

campo($nombreCampo)

Obtiene cualquier campo de la tabla gen_usuarios para el usuario actual. La información se carga bajo demanda (lazy loading) la primera vez que se solicita un campo.

// Obtener el email o cualquier campo personalizado
$email = service('Admin_aut')->getField('usu_email');

Arquitectura de Drivers (RagnosAuthInterface)

A partir de Ragnos Framework v1.1+, el sistema de autenticación está desacoplado bajo el patrón Adapter/Driver. Esto permite intercambiar la capa de autenticación sin alterar la API pública documentada (service('Admin_aut'), $this->checkLogin(), $this->checkUserInGroup(), bitácoras de auditoría, etc.).

Drivers Disponibles

  1. native (Por defecto):
  2. Basado en sesiones nativas de PHP y las tablas gen_usuarios y gen_gruposdeusuarios.
  3. Incluye soporte para Bearer Tokens en peticiones API contra usu_token.
  4. Comparación de roles insensible a mayúsculas/minúsculas.
  5. shield:
  6. Integración directa con CodeIgniter 4 Shield.
  7. Mapea llamadas a las APIs de Shield (auth(), auth()->user(), auth('tokens'), etc.).
  8. Si Shield no está instalado en el proyecto, el sistema realiza automáticamente un fallback seguro hacia el driver nativo.

Configuración del Driver

Puedes definir el driver activo en app/Config/RagnosConfig.php:

public string $authDriver = 'native'; // Opciones: 'native' | 'shield'

O sobreescribirlo por entorno en tu archivo .env:

ragnos.authDriver = shield

Métodos del Contrato RagnosAuthInterface

Todos los drivers implementan App\ThirdParty\Ragnos\Auth\RagnosAuthInterface:

Método Tipo Retorno Descripción
checkLogin() bool Retorna true si hay un usuario autenticado.
isUserInGroup(string $group) bool Comprueba pertenencia al grupo indicado.
getUserId() ?int Identificador único del usuario o null.
getUserName() ?string Nombre del usuario autenticado o null.
getUserEmail() ?string Correo electrónico del usuario o null.
logout() void Cierra la sesión activa del usuario.
checkApiToken(string $token) bool Valida un token Bearer para peticiones API.

Para mantener 100% de retrocompatibilidad, los drivers y el servicio Admin_aut también exponen los métodos clásicos $auth->isLoggedIn(), $auth->id(), $auth->name(), $auth->getField($field) y $auth->checkUserInGroup($grupos).


Autenticación vía API

El sistema soporta autenticación para APIs REST de forma transparente.

  1. Al hacer login, se genera un token seguro en usu_token.
  2. El cliente debe enviar este token en el header Authorization.
  3. checkLogin() detecta automáticamente si la petición es una llamada API (isApiCall()) y valida el token en lugar de la sesión de PHP.

Esto permite utilizar los mismos controladores para la interfaz web y para aplicaciones móviles o frontends desacoplados.

Ejemplo Completo

<?php

namespace App\Controllers;

use App\ThirdParty\Ragnos\Controllers\BaseController;

class Pedidos extends BaseController
{
    public function __construct()
    {
        // Cargar helpers necesarios
        helper(['form', 'url']);
    }

    public function index()
    {
        // 1. Asegurar que esté logueado
        $this->checkLogin();

        $auth = service('Admin_aut');

        // 2. Obtener datos del usuario
        $data['usuario'] = $auth->name();
        $data['esAdmin'] = $auth->isUserInGroup('Administrador');

        return view('pedidos/index', $data);
    }

    public function eliminar($id)
    {
        // 3. Restricción estricta: Solo Admins pueden eliminar
        $this->checkUserInGroup('Administrador');

        $model = new \App\Models\PedidosModel();
        $model->delete($id);

        return redirect()->to('/pedidos');
    }
}