Saltar a contenido

🛠 Unidad ISS-19 · Logout — capa 🛠 CONSTRUIR

✅ GATE de la unidad

Capa Página Para qué
🧠 Aprender — no está en la fuente comprender, explicar y relacionar
🛠 Construir esta página ejecutar, programar y verificar
✅ GATE Condiciones de cierre condición para pasar al bloque siguiente

Esta es la guía ejecutable. El cuerpo de abajo es el ISS técnico verbatim: comandos, rutas, versiones, verificaciones y criterios, sin simplificar.

Guía de estudio. Esta unidad no tiene cuaderno en material/django/iss/ISS-19/aprendizaje/. La página publica solo el ISS técnico.


ISS-19 — Logout

Objetivo

Invalidar el refresh presentado, sin guardar el access token.

Requisitos

  • ISS-18 superado.

Construcción

LogoutAPIView es OPEN. Recibe {"refresh": "..."}. La clase se agrega en el archivo de vistas, que ya tiene login y refresh.

ARCHIVO: apps/security/auth_views.py

UBICAR el import de serializers y AGREGAR LogoutSerializer.

ENCIMA DE:
def _find_user(username, email):

AGREGAR LogoutAPIView. Si el hash no existe, 401. Si el token ya fue
reemplazado, revoca la familia y responde 401. En cualquier otro caso
lo deja inactive, escribe revoked_at y responde 204.
ARCHIVO: apps/security/urls.py

UBICAR:
from apps.security.auth_views import LoginAPIView, RefreshAPIView

REEMPLAZAR POR:
from apps.security.auth_views import LoginAPIView, LogoutAPIView, RefreshAPIView

DEBAJO DE:
    path("auth/refresh/", RefreshAPIView.as_view(), name="auth-refresh"),

AGREGAR:
    path("auth/logout/", LogoutAPIView.as_view(), name="auth-logout"),
hash desconocido          → 401
token ya reemplazado      → revoca la familia → 401
en cualquier otro caso    → status inactive, revoked_at = ahora → 204

Un segundo logout del mismo token, si no fue rotado, vuelve a dejarlo inactivo y responde 204.

La prueba sigue en OPEN.

ARCHIVO: apps/security/tests.py

AL FINAL DE class AuthFlowTests, AGREGAR:

    def test_logout_invalidates_refresh(self):
        login = self.client.post(
            "/api/auth/login/",
            {"username": "ana", "password": PASSWORD},
            format="json",
        )
        raw = login.data["refresh"]
        logout = self.client.post("/api/auth/logout/", {"refresh": raw}, format="json")
        self.assertEqual(logout.status_code, status.HTTP_204_NO_CONTENT)
        again = self.client.post("/api/auth/refresh/", {"refresh": raw}, format="json")
        self.assertEqual(again.status_code, status.HTTP_401_UNAUTHORIZED)
python manage.py test apps.security.tests.AuthFlowTests.test_logout_invalidates_refresh

Explicación

Logout no pide access token. La credencial de la sesión persistida es el refresh. Cerrar sesión en un dispositivo no tiene por qué cerrar otra familia. Si el valor presentado ya fue rotado, se trata como reuso y sí se apaga la familia: alguien está presentando un token que ya no debía existir.

No hay tabla de access tokens que limpiar.

Cómo probarlo

Capa HTTP, acceso OPEN. Logout no lleva Bearer. El cuerpo lleva el refresh que acaba de emitir el login.

python manage.py test apps.security.tests.AuthFlowTests.test_logout_invalidates_refresh
        │
        ▼
login  →  refresh R          fila active en refresh_tokens
        │
        ▼
POST /api/auth/logout/       {refresh: R}     204
        │
        ▼
POST /api/auth/refresh/      {refresh: R}     401

En Swagger, sin Authorize: login, copie refresh, POST /api/auth/logout/ y vuelva a presentarlo en POST /api/auth/refresh/. La segunda llamada responde 401.

swagger-ui   OPEN
  login → refresh R
  POST /api/auth/logout/    R     204
  POST /api/auth/refresh/   R     401

Criterios de aceptación

  • AC-19-01: logout responde 204.
  • AC-19-02: ese refresh ya no puede renovar: el siguiente refresh responde 401.

Verificación

test_logout_invalidates_refresh.

Evidencias

  • EVI-19-01: test PASS.

GATE

AC Verificación Evidencia Resultado
AC-19-01 HTTP 204 EVI-19-01 PASS
AC-19-02 refresh posterior 401 EVI-19-01 PASS

✅ GATE de la unidad ISS-19 — este bloque no añade ningún criterio nuevo.

Las condiciones de cierre son las de esta misma página:

Con el GATE en verde queda habilitado el bloque siguiente de la ruta.

Navegación de la ruta: ← ISS-18 · 🛠 Construir · ↑ Ruta Django · → ISS-20 · 🛠 Construir