Autenticación

Authentication

SIUD soporta dos mecanismos de autenticación según el tipo de cliente: sesión Django para la interfaz web y JWT (SimpleJWT) para las APIs REST.

Resumen: Sesión para navegadores (interfaz web)  ·  JWT para integraciones y APIs externas  ·  Rate limit: 5 intentos/minuto por IP

1. Autenticación por Sesión (Web UI)

El login basado en sesión es para usuarios que acceden a través del navegador. Devuelve una cookie de sesión que el navegador envía automáticamente en cada petición posterior.

PropiedadValor
MétodoGET / POST
Ruta/login/
Autenticación requeridaNinguna
Rate limit5 req/minuto por IP

Parámetros (POST form)

CampoTipoRequeridoDescripción
usernamestringNombre de usuario
passwordstringContraseña

Respuestas

CódigoDescripción
302Login exitoso — redirige a /modulos/
200Credenciales inválidas — retorna el formulario con error
429Demasiados intentos — rate limit alcanzado

Timeout de sesión

Las sesiones expiran tras 20 minutos de inactividad. El middleware de autenticación redirige automáticamente a /login/ cuando la sesión expira.

Rutas exentas del control de sesión: /back/, /api/, /api-siud/, /static/, /media/, /login/, /recuperar-password/.

2. Autenticación JWT (APIs REST)

Para integraciones externas y clientes que no usan sesión, SIUD expone endpoints JWT mediante djangorestframework-simplejwt.

Obtener tokens

PropiedadValor
MétodoPOST
Ruta/api/token/
Content-Typeapplication/json
Autenticación requeridaNinguna
POST /api/token/
Content-Type: application/json

{
  "username": "usuario@ejemplo.com",
  "password": "contraseña_segura"
}
import requests

resp = requests.post(
    "https://TU-DOMINIO/api/token/",
    json={"username": "usuario@ejemplo.com", "password": "contraseña_segura"}
)
data = resp.json()
access  = data["token"]["access"]
refresh = data["token"]["refresh"]
const { data } = await axios.post(
  'https://TU-DOMINIO/api/token/',
  { username: 'usuario@ejemplo.com', password: 'contraseña_segura' }
);
const { access, refresh } = data.token;
var body = new StringContent(
    JsonSerializer.Serialize(new {
        username = "usuario@ejemplo.com",
        password = "contraseña_segura"
    }),
    Encoding.UTF8, "application/json"
);
var response = await client.PostAsync("https://TU-DOMINIO/api/token/", body);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://TU-DOMINIO/api/token/"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(
        "{\"username\":\"usuario@ejemplo.com\",\"password\":\"contraseña_segura\"}"
    ))
    .build();

Respuesta exitosa (200):

{
  "token": {
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
  },
  "msg": "Login success"
}

Configuración de tokens

TokenVida útilAlgoritmo
Access Token20 minutosHS256
Refresh Token1 díaHS256

Renovar access token

PropiedadValor
MétodoPOST
Ruta/api/token/refresh/
Content-Typeapplication/json
POST /api/token/refresh/
Content-Type: application/json

{ "refresh": "eyJ0eXAiOiJKV1Qi..." }
import requests

resp = requests.post(
    "https://TU-DOMINIO/api/token/refresh/",
    json={"refresh": refresh_token}
)
access = resp.json()["access"]
const { data } = await axios.post(
  'https://TU-DOMINIO/api/token/refresh/',
  { refresh: refreshToken }
);
const newAccess = data.access;
var body = new StringContent(
    JsonSerializer.Serialize(new { refresh = refreshToken }),
    Encoding.UTF8, "application/json"
);
var response = await client.PostAsync(
    "https://TU-DOMINIO/api/token/refresh/", body);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://TU-DOMINIO/api/token/refresh/"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(
        "{\"refresh\":\"" + refreshToken + "\"}"
    ))
    .build();

Response 200:

{ "access": "eyJ0eXAiOiJKV1Qi..." }

Uso del token en peticiones

Incluir el access token en el header Authorization de cada petición a la API:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

Endpoints con JWT vs Sesión

Algunos endpoints tienen variantes para cada tipo de autenticación:

Endpoint (Sesión)Endpoint (JWT)Descripción
/api/ejecutar/<codigo>/api/ejecutar-token/<codigo>Ejecución de acciones

3. Recuperación de contraseña

EndpointMétodoDescripción
/recuperar-password/GET / POSTFormulario — envía email con token de recuperación
/recuperar-password/<token>/GET / POSTFormulario — establece nueva contraseña con el token recibido

Parámetros del formulario de recuperación (POST)

CampoTipoDescripción
emailstringEmail registrado del usuario

Parámetros para reseteo de contraseña (POST)

CampoTipoDescripción
passwordstringNueva contraseña
password_confirmstringConfirmación de la nueva contraseña

4. Medidas de seguridad

MedidaDetalle
Rate limiting5 intentos de login / minuto por IP (django-ratelimit)
Timeout de sesión20 minutos de inactividad (middleware)
CSRFActivo en todos los endpoints de formulario
X-Frame-OptionsSAMEORIGIN — previene clickjacking
Content-Type SniffSECURE_CONTENT_TYPE_NOSNIFF = True
CORSRestringido a orígenes configurados
Hashing de contraseñasPBKDF2, Argon2, BCrypt soportados

5. Permisos en la API

La clase de permiso por defecto en DRF es IsAuthenticated. Los endpoints públicos (login, recuperación de contraseña) usan AllowAny.

El admin de Django (/back/) requiere que el usuario tenga el flag is_staff = True.