2026-08-17 10:34:12 -05:00
|
|
|
# Flujo de Autenticación
|
|
|
|
|
|
|
|
|
|
## Login
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
participant F as Frontend
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
participant S as core/session.py
|
|
|
|
|
participant SAP_C as core/sap.py
|
|
|
|
|
participant SAP as SAP Service Layer
|
|
|
|
|
|
|
|
|
|
F->>API: POST /api/Login\n{Username, Password}
|
2026-08-17 11:58:38 -05:00
|
|
|
Note over F,API: Username = webUser (U_WEB_USER)\nPassword = U_WEB_PASS
|
2026-08-17 10:34:12 -05:00
|
|
|
|
2026-08-17 11:58:38 -05:00
|
|
|
API->>SAP_C: forward_to_sapb1(GET, "EmployeesInfo")\n$filter=U_WEB_USER eq '{webUser}'
|
|
|
|
|
SAP_C->>SAP: GET /b1s/v1/EmployeesInfo?$filter=...
|
|
|
|
|
SAP-->>SAP_C: {EmployeeID, FirstName, LastName, Active, U_WEB_PASS, ...}
|
|
|
|
|
SAP_C-->>API: Employee data (o lista vacía)
|
2026-08-17 10:34:12 -05:00
|
|
|
|
2026-08-17 11:58:38 -05:00
|
|
|
API->>API: ¿Existe empleado?\n¿Active == "tYES"?\n¿U_WEB_PASS == Password?
|
|
|
|
|
alt Todo válido
|
|
|
|
|
API->>S: create_employee_session(webUser, empId, first_name, last_name)
|
|
|
|
|
S->>S: Genera token_urlsafe(32)\n(invalida token anterior del mismo webUser)
|
2026-08-17 10:34:12 -05:00
|
|
|
S-->>API: token
|
|
|
|
|
|
|
|
|
|
API->>SAP_C: ensure_sap_session()
|
|
|
|
|
SAP_C->>SAP: POST /Login (manager creds)
|
|
|
|
|
SAP-->>SAP_C: B1SESSION cookie
|
|
|
|
|
SAP_C-->>API: OK
|
|
|
|
|
|
2026-08-17 11:58:38 -05:00
|
|
|
API-->>F: 200 {message, token, username: FirstName, company: CompanyDB}
|
|
|
|
|
else No existe / inactivo / password no coincide
|
|
|
|
|
API-->>F: 401 (mensaje según el caso: "Usuario no registrado",\n"Usuario inactivo" o "Usuario o contraseña incorrectos")
|
2026-08-17 10:34:12 -05:00
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Logout
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
participant F as Frontend
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
participant S as core/session.py
|
|
|
|
|
|
|
|
|
|
F->>API: POST /api/Logout\nX-Session-Token: <token>
|
|
|
|
|
API->>S: remove_employee_session_by_token(token)
|
|
|
|
|
S->>S: Elimina active_tokens[token]\ny employee_sessions[emp_id]
|
|
|
|
|
S-->>API: OK
|
|
|
|
|
API-->>F: 200 {message: "Sesión cerrada"}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Validación de Sesión (Middleware)
|
|
|
|
|
|
|
|
|
|
Cada petición a `/api/*` (excepto `/api/Login`) pasa por el `session_middleware`:
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
participant F as Frontend
|
|
|
|
|
participant MW as session_middleware
|
|
|
|
|
participant S as core/session.py
|
|
|
|
|
participant R as Router
|
|
|
|
|
|
|
|
|
|
F->>MW: Request /api/Items\nX-Session-Token: <token>
|
|
|
|
|
|
|
|
|
|
MW->>S: validate_and_refresh_session(token)
|
|
|
|
|
S->>S: Busca token en active_tokens
|
|
|
|
|
|
|
|
|
|
alt Token válido
|
|
|
|
|
S->>S: Actualiza last_activity
|
2026-08-17 11:58:38 -05:00
|
|
|
S-->>MW: webUser
|
|
|
|
|
MW->>MW: set_current_user(webUser, full_name, emp_id)\nrequest.state.webUser = webUser
|
2026-08-17 10:34:12 -05:00
|
|
|
MW->>R: Continúa al router
|
|
|
|
|
R-->>F: 200 Response
|
|
|
|
|
else Token expirado (>30 min)
|
|
|
|
|
S->>S: Elimina token y sesión
|
|
|
|
|
S-->>MW: None
|
|
|
|
|
MW-->>F: 401 Token expirado
|
|
|
|
|
else Token no existe
|
|
|
|
|
S-->>MW: None
|
|
|
|
|
MW-->>F: 401 No autorizado
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Ciclo de Vida de la Sesión de Empleado
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
stateDiagram-v2
|
|
|
|
|
[*] --> Activa: Login exitoso\ngenera token
|
|
|
|
|
Activa --> Expirada: 30 min sin actividad
|
|
|
|
|
Activa --> Cerrada: Logout explícito
|
|
|
|
|
Expirada --> [*]
|
|
|
|
|
Cerrada --> [*]
|
|
|
|
|
|
|
|
|
|
note right of Activa
|
|
|
|
|
Se refresca last_activity
|
|
|
|
|
en cada petición válida
|
|
|
|
|
end note
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Mecanismo de Renovación
|
|
|
|
|
|
|
|
|
|
La sesión del empleado se renueva automáticamente en **cada petición válida**:
|
|
|
|
|
|
|
|
|
|
1. El frontend envía `X-Session-Token` en el header
|
|
|
|
|
2. `validate_and_refresh_session()` actualiza `last_activity` al timestamp actual
|
|
|
|
|
3. El timeout de 30 minutos se mide desde la última actividad
|
|
|
|
|
4. Si pasan 30 min sin peticiones, el token se invalida automáticamente
|