Práctica 4 Parte III — Proteger rutas con Nginx Proxy Manager y Flask
La aplicación Tomcat no debe ser accesible directamente desde fuera por su puerto interno.
Si el usuario puede entrar directamente a:
http://IP_DEL_SERVIDOR:8080/vistas/carrito.jsp
entonces se saltaría Nginx Proxy Manager y también se saltaría Flask.
La idea correcta es:
Usuario -> java.damx.es -> Nginx Proxy Manager -> Tomcat
No:
Usuario -> IP:8080 -> Tomcat
1. Objetivo de la práctica
En esta práctica vamos a usar Nginx Proxy Manager como reverse proxy y un servicio Flask como servidor central de autenticación.
La idea es que Nginx Proxy Manager no gestione usuarios directamente. En su lugar, antes de dejar pasar a una ruta protegida, preguntará a Flask:
¿Este usuario está autenticado y tiene el rol necesario?
Si Flask responde:
| Respuesta de Flask | Significado |
|---|---|
204 | Acceso permitido |
401 | Usuario no autenticado |
403 | Usuario autenticado, pero sin permisos |
2. Esquema general
Navegador
|
| http://java.damx.es/vistas/carrito.jsp
v
Nginx Proxy Manager
|
|-- consulta interna --> Flask /auth/verify
| ¿tiene sesión? ¿tiene rol?
|
|<-- 204 / 401 / 403
|
v
Tomcat / JSP
En esta práctica trabajaremos con tres servicios:
Nginx Proxy Manager -> reverse proxy
Flask -> login y autorización
Tomcat -> aplicación Java/JSP
3. Requisitos previos
Antes de empezar, deben funcionar estas partes:
- La aplicación Flask debe estar arrancada.
- La aplicación Tomcat/JSP debe estar arrancada.
- Nginx Proxy Manager debe poder llegar a Flask y a Tomcat.
- Los contenedores deben compartir una red Docker común.
Ejemplo de nombres usados en esta práctica:
Flask: flask-auth-flaskapp-1:8888
Tomcat: proyectoweb-tomcat-1:8080
Dominio: java.damx.es
Si tus contenedores tienen otros nombres, tendrás que cambiarlos en la configuración.
4. Comprobar que Nginx Proxy Manager ve los contenedores
Debes verificar que todos los contenedores esten en la misma red (proxy)
5. Configurar el Proxy Host principal
En Nginx Proxy Manager:
Proxy Hosts -> Add Proxy Host
En la pestaña Details:
Domain Names: java.damx.es
Scheme: http
Forward Hostname / IP: proyectoweb-tomcat-1
Forward Port: 8080
Access List: Publicly Accessible
Guarda.
Ahora prueba:
http://java.damx.es/
Debe cargar la aplicación Tomcat/JSP.
Si aparece la pantalla:
Congratulations! You've successfully started the Nginx Proxy Manager.
significa que Nginx Proxy Manager no está encontrando el proxy host para ese dominio.
6. Crear rutas públicas para login y logout
El login no debe ir a Tomcat, sino a Flask.
En el proxy host java.damx.es, entra en Custom Locations y añade:
Ruta /login
Location: /login
Scheme: http
Forward Hostname / IP: flask-auth-flaskapp-1
Forward Port: 8888
La caja de configuración personalizada se deja vacía.
Ruta /logout
Location: /logout
Scheme: http
Forward Hostname / IP: flask-auth-flaskapp-1
Forward Port: 8888
La caja de configuración personalizada se deja vacía.
Con esto:
http://java.damx.es/login
http://java.damx.es/logout
serán atendidas por Flask.
7. Configuración avanzada de Nginx Proxy Manager
Ahora vamos a crear rutas internas que Nginx usará para preguntar a Flask.
En el proxy host java.damx.es, entra en la pestaña de la rueda, Advanced, y pega:
location = /_flask_auth_admin {
internal;
proxy_pass http://flask-auth-flaskapp-1:8888/auth/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Required-Roles "admin";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /_flask_auth_cliente {
internal;
proxy_pass http://flask-auth-flaskapp-1:8888/auth/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Required-Roles "cliente";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /_flask_auth_admin_cliente {
internal;
proxy_pass http://flask-auth-flaskapp-1:8888/auth/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Required-Roles "admin,cliente";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /_flask_auth_login {
internal;
proxy_pass http://flask-auth-flaskapp-1:8888/auth/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Required-Roles "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location @login_redirect {
return 302 /login?next=$request_uri;
}
location @forbidden {
return 403;
}
Explicación rápida
location = /_flask_auth_admin
Crea una ruta interna de Nginx. El usuario no puede entrar directamente a ella porque lleva:
internal;
Esta línea llama a Flask:
proxy_pass http://flask-auth-flaskapp-1:8888/auth/verify;
Esta línea indica qué rol se exige:
proxy_set_header X-Required-Roles "admin";
Flask leerá esa cabecera y decidirá si el usuario puede pasar.
8. Proteger una ruta JSP concreta
Vamos a proteger:
http://java.damx.es/vistas/carrito.jsp
En Custom Locations, añade:
Location: /vistas/carrito.jsp
Scheme: http
Forward Hostname / IP: proyectoweb-tomcat-1
Forward Port: 8080
En la caja grande de configuración personalizada:
auth_request /_flask_auth_admin;
error_page 401 = @login_redirect;
error_page 403 = @forbidden;
Esto significa:
/vistas/carrito.jsp -> requiere rol admin
9. Proteger una ruta para cliente
Para proteger una ruta que solo puede ver un usuario con rol cliente:
auth_request /_flask_auth_cliente;
error_page 401 = @login_redirect;
error_page 403 = @forbidden;
10. Proteger una ruta para admin o cliente
Para permitir tanto admin como cliente:
auth_request /_flask_auth_admin_cliente;
error_page 401 = @login_redirect;
error_page 403 = @forbidden;
11. Proteger una ruta solo con login
Si no quieres exigir un rol concreto, solo que el usuario esté autenticado:
auth_request /_flask_auth_login;
error_page 401 = @login_redirect;
error_page 403 = @forbidden;
12. Qué debe hacer Flask
Flask debe tener este endpoint:
@app.route("/auth/verify")
def auth_verify():
if not session.get("login"):
return "", 401
roles_usuario = session.get("roles", [])
if isinstance(roles_usuario, str):
roles_usuario = [roles_usuario]
roles_requeridos = request.headers.get("X-Required-Roles", "").strip()
if not roles_requeridos:
return "", 204
lista_roles_requeridos = [
rol.strip()
for rol in roles_requeridos.split(",")
if rol.strip()
]
for rol in lista_roles_requeridos:
if rol in roles_usuario:
return "", 204
return "", 403
Flask no necesita saber si la ruta es:
/vistas/carrito.jsp
/vistas/insertar.jsp
/ProductoControlador
Eso lo decide Nginx Proxy Manager.
Flask solo sabe esto:
¿El usuario está logueado?
¿Tiene alguno de los roles pedidos por Nginx?
13. Flujo completo de prueba
Primero cerramos sesión:
http://java.damx.es/logout
Luego intentamos entrar a:
http://java.damx.es/vistas/carrito.jsp
Como no hay sesión, Flask devuelve:
401
Nginx redirige a:
/login?next=/vistas/carrito.jsp
Después hacemos login.
Si el usuario tiene rol admin, entrará.
Si el usuario tiene rol cliente, recibirá:
403 Forbidden
14. Logs de depuración en Flask
Para ver qué está pasando, podemos mirar los logs:
docker logs -f flask-auth-flaskapp-1
Ejemplo correcto si rafa es cliente e intenta entrar a una ruta de admin:
AUTH usuario: rafa
AUTH roles_usuario: ['cliente']
AUTH roles_requeridos: admin
AUTH uri: /vistas/carrito.jsp
AUTH denegado