Tiempo de lectura: 2 minutos
Hoy vamos a aprender cómo podemos añadir una contraseña de acceso a Swagger en FastAPI. De esta forma securizaremos en dashboard de Swagger y el json de definiciones.
Lo primero que haremos es ir al main.py de FastAPI.
Vamos a crear un Middleware que nos permitirá interceptar las llamadas al endpoint /openapi.json y /docs y solicitaremos un usuario y contraseña en esos endpoints.
from dotenv import load_dotenv
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
# Configuración de la autenticación básica
valid_username = os.getenv("SWAGGER_USER")
valid_password = os.getenv("SWAGGER_PASSWORD")
def authenticate(credentials: HTTPBasicCredentials = Depends()):
if credentials.username != valid_username or credentials.password != valid_password:
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
# Middleware para autenticar las rutas de documentación
class AuthDocsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# Verificamos si es una solicitud a /docs o /openapi.json (y cualquier otra ruta que contenga "openapi.json")
if "/openapi.json" in request.url.path or "/docs" in request.url.path:
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Basic "):
# Si no hay encabezado Authorization, respondemos con 401 y el encabezado WWW-Authenticate
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Missing or invalid authorization header"},
headers={"WWW-Authenticate": "Basic"},
# Extraemos y decodificamos las credenciales
base64_credentials = auth_header[6:] # Eliminamos el prefijo "Basic "
decoded_credentials = base64.b64decode(base64_credentials).decode("utf-8")
username, password = decoded_credentials.split(":", 1)
# Creamos el objeto de credenciales
credentials = HTTPBasicCredentials(username=username, password=password)
# Ejecutamos la función de autenticación
authenticate(credentials)
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Incorrect username or password"},
headers={"WWW-Authenticate": "Basic"},
return await call_next(request)
# Agregamos el middleware
app.add_middleware(AuthDocsMiddleware)
import os
from dotenv import load_dotenv
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
import base64
load_dotenv()
# Configuración de la autenticación básica
security = HTTPBasic()
valid_username = os.getenv("SWAGGER_USER")
valid_password = os.getenv("SWAGGER_PASSWORD")
def authenticate(credentials: HTTPBasicCredentials = Depends()):
if credentials.username != valid_username or credentials.password != valid_password:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
# Middleware para autenticar las rutas de documentación
class AuthDocsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# Verificamos si es una solicitud a /docs o /openapi.json (y cualquier otra ruta que contenga "openapi.json")
if "/openapi.json" in request.url.path or "/docs" in request.url.path:
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Basic "):
# Si no hay encabezado Authorization, respondemos con 401 y el encabezado WWW-Authenticate
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Missing or invalid authorization header"},
headers={"WWW-Authenticate": "Basic"},
)
# Extraemos y decodificamos las credenciales
try:
base64_credentials = auth_header[6:] # Eliminamos el prefijo "Basic "
decoded_credentials = base64.b64decode(base64_credentials).decode("utf-8")
username, password = decoded_credentials.split(":", 1)
# Creamos el objeto de credenciales
credentials = HTTPBasicCredentials(username=username, password=password)
# Ejecutamos la función de autenticación
authenticate(credentials)
except Exception as e:
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Incorrect username or password"},
headers={"WWW-Authenticate": "Basic"},
)
return await call_next(request)
# Agregamos el middleware
app.add_middleware(AuthDocsMiddleware)
import os
from dotenv import load_dotenv
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
import base64
load_dotenv()
# Configuración de la autenticación básica
security = HTTPBasic()
valid_username = os.getenv("SWAGGER_USER")
valid_password = os.getenv("SWAGGER_PASSWORD")
def authenticate(credentials: HTTPBasicCredentials = Depends()):
if credentials.username != valid_username or credentials.password != valid_password:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
# Middleware para autenticar las rutas de documentación
class AuthDocsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# Verificamos si es una solicitud a /docs o /openapi.json (y cualquier otra ruta que contenga "openapi.json")
if "/openapi.json" in request.url.path or "/docs" in request.url.path:
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Basic "):
# Si no hay encabezado Authorization, respondemos con 401 y el encabezado WWW-Authenticate
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Missing or invalid authorization header"},
headers={"WWW-Authenticate": "Basic"},
)
# Extraemos y decodificamos las credenciales
try:
base64_credentials = auth_header[6:] # Eliminamos el prefijo "Basic "
decoded_credentials = base64.b64decode(base64_credentials).decode("utf-8")
username, password = decoded_credentials.split(":", 1)
# Creamos el objeto de credenciales
credentials = HTTPBasicCredentials(username=username, password=password)
# Ejecutamos la función de autenticación
authenticate(credentials)
except Exception as e:
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Incorrect username or password"},
headers={"WWW-Authenticate": "Basic"},
)
return await call_next(request)
# Agregamos el middleware
app.add_middleware(AuthDocsMiddleware)
Ahora crearemos un archivo .env con los credenciales necesarios:
.env
SWAGGER_USER="admin"
SWAGGER_PASS="admin123"
SWAGGER_USER="admin"
SWAGGER_PASS="admin123"
Y cuándo accedamos al Swagger /docs nos pedirá autenticación:
Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.
Post Views: 7
Relacionado