From: Giorgio Ravera Date: Tue, 6 Jan 2026 14:09:04 +0000 (+0100) Subject: Added middleware for login management X-Git-Tag: v0.0.1~41 X-Git-Url: http://git.giorgioravera.it/?a=commitdiff_plain;h=db2aa0f3dcb049bb713ec80dab0c72e2ae80df4a;p=network-manager.git Added middleware for login management --- diff --git a/backend/main.py b/backend/main.py index 4f9f5f8..d7c4652 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,20 +1,12 @@ # backend/main.py # import standard modules -from fastapi import FastAPI -from fastapi import Request, Response +from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse, RedirectResponse +from fastapi.responses import FileResponse, RedirectResponse, JSONResponse import os # Import local modules -from backend.security import is_logged_in, require_login, html_protected -from backend.db.hosts import ( - get_hosts, - get_host, - add_host, - update_host, - delete_host -) +from backend.security import is_logged_in from backend.routes.health import router as health_router from backend.routes.login import router as login_router from backend.routes.hosts import router as hosts_router @@ -39,19 +31,49 @@ app.add_middleware( ) # --------------------------------------------------------- -# FRONTEND PATHS (absolute paths inside Docker) +# Middleware to manage Login # --------------------------------------------------------- -# Protect html pages -def html_protected(request: Request, filename: str): +@app.middleware("http") +async def session_middleware(request: Request, call_next): + path = request.url.path + + # Excludes the login methods + if path.startswith("/login") or path.startswith("/api/login"): + return await call_next(request) + + # Excludes static files + if ( + path.startswith("/css") or + path.startswith("/js") or + path.endswith(".js") or + path.endswith(".css") or + path.endswith(".png") or + path.endswith(".jpg") or + path.endswith(".ico") + ): + return await call_next(request) + + # Protected APIs + if path.startswith("/api"): + if not is_logged_in(request): + return JSONResponse({"error": "Not authenticated"}, status_code=401) + return await call_next(request) + + # Protected HTML pages if not is_logged_in(request): return RedirectResponse("/login") - return FileResponse(os.path.join(FRONTEND_DIR, filename)) + + return await call_next(request) + +# --------------------------------------------------------- +# FRONTEND PATHS (absolute paths inside Docker) +# --------------------------------------------------------- # Homepage @app.get("/") def home(request: Request): - return html_protected(request, "hosts.html") + return FileResponse(os.path.join(FRONTEND_DIR, "hosts.html")) # Serve app.js @app.get("/app.js") diff --git a/backend/routes/hosts.py b/backend/routes/hosts.py index 0376d2d..ecbebf6 100644 --- a/backend/routes/hosts.py +++ b/backend/routes/hosts.py @@ -6,7 +6,6 @@ from fastapi.responses import FileResponse, RedirectResponse import os import ipaddress # Import local modules -from backend.security import is_logged_in, require_login, html_protected from backend.db.hosts import ( get_hosts, get_host, @@ -27,7 +26,7 @@ router = APIRouter() # Hosts page @router.get("/hosts") def hosts(request: Request): - return html_protected(request, "hosts.html") + return FileResponse(os.path.join(FRONTEND_DIR, "hosts.html")) # Serve hosts.css @router.get("/css/hosts.css") @@ -40,12 +39,10 @@ def css_hosts(): @router.get("/api/hosts") def api_get_hosts(request: Request): - require_login(request) return get_hosts() @router.post("/api/hosts") def api_add_host(request: Request, data: dict): - require_login(request) name = data.get("name", "").strip() ipv4 = data.get("ipv4") ipv6 = data.get("ipv6") @@ -65,12 +62,10 @@ def api_add_host(request: Request, data: dict): @router.get("/api/hosts/{host_id}") def api_get_host(request: Request, host_id: int): - require_login(request) return get_host(host_id) or {} @router.put("/api/hosts/{host_id}") def api_update_host(request: Request, data: dict, host_id: int): - require_login(request) name = data.get("name", "").strip() ipv4 = data.get("ipv4") ipv6 = data.get("ipv6") @@ -91,6 +86,5 @@ def api_update_host(request: Request, data: dict, host_id: int): @router.delete("/api/hosts/{host_id}") def api_delete_host(request: Request, host_id: int): - require_login(request) delete_host(host_id) return {"status": "ok"} diff --git a/backend/routes/login.py b/backend/routes/login.py index 88b358c..adfb98f 100644 --- a/backend/routes/login.py +++ b/backend/routes/login.py @@ -6,7 +6,7 @@ from fastapi.responses import FileResponse, RedirectResponse import os import time # Import local modules -from backend.security import is_logged_in, signer +from backend.security import signer from backend.db.users import verify_login # Import config variables from backend.config import FRONTEND_DIR, LOGIN_MAX_ATTEMPTS, LOGIN_WINDOW_SECONDS @@ -37,8 +37,6 @@ def check_rate_limit(ip: str): # Login page @router.get("/login") def login_page(request: Request): - if is_logged_in(request): - return RedirectResponse("/") return FileResponse(os.path.join(FRONTEND_DIR, "login.html")) # Serve login.css diff --git a/backend/security.py b/backend/security.py index b31f092..a79148f 100644 --- a/backend/security.py +++ b/backend/security.py @@ -3,7 +3,6 @@ # import standard modules import os from fastapi import Request, HTTPException -from fastapi.responses import FileResponse, RedirectResponse from itsdangerous import TimestampSigner # Import config variables from backend.config import FRONTEND_DIR, SECRET_KEY @@ -11,7 +10,7 @@ from backend.config import FRONTEND_DIR, SECRET_KEY signer = TimestampSigner(SECRET_KEY) # ----------------------------- -# login check +# check session cookie # ----------------------------- def is_logged_in(request: Request) -> bool: token = request.cookies.get("session") @@ -24,16 +23,8 @@ def is_logged_in(request: Request) -> bool: return False # ----------------------------- -# login check (for api) +# check login # ----------------------------- def require_login(request: Request): if not is_logged_in(request): raise HTTPException(status_code=401, detail="Not authenticated") - -# ----------------------------- -# login check (for html) -# ----------------------------- -def html_protected(request: Request, filename: str): - if not is_logged_in(request): - return RedirectResponse("/login") - return FileResponse(os.path.join(FRONTEND_DIR, filename)) \ No newline at end of file