fix(auth): 401 dal backend svuota la sessione e segnala session_expired (#25)
api_client._handle_response: su 401 pulisce la sessione Flask e marca g.session_expired. Un solo after_request (app.py) trasforma le pagine HTML rimaste in piedi con un errore generico in un redirect al login con flash; le route JSON/AJAX che già inoltrano il dict di api_client (measure.py, statistics.py) ricevono session_expired nel corpo insieme al 401. Backend (riuso della key, bcrypt a tempo costante) resta al lotto A2. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
from flask import has_request_context, request, session
|
||||
from flask import g, has_request_context, request, session
|
||||
|
||||
from config import Config
|
||||
|
||||
@@ -39,6 +39,21 @@ class APIClient:
|
||||
headers["X-Real-IP"] = client_ip
|
||||
return headers
|
||||
|
||||
@staticmethod
|
||||
def _handle_session_expired() -> None:
|
||||
"""The backend says our api_key is no longer valid (#25).
|
||||
|
||||
One point for the whole app: whichever route made the call, the
|
||||
Flask session is emptied here so nothing downstream keeps acting as
|
||||
that user. A flag is left on ``g`` for the single after_request
|
||||
hook in app.py to turn into a redirect-to-login on HTML pages; JSON
|
||||
callers already get ``session_expired`` in the body returned below.
|
||||
"""
|
||||
if not has_request_context():
|
||||
return
|
||||
session.clear()
|
||||
g.session_expired = True
|
||||
|
||||
def _handle_response(self, response: requests.Response) -> dict[str, Any]:
|
||||
"""Parse response and return normalized dict.
|
||||
|
||||
@@ -46,12 +61,16 @@ class APIClient:
|
||||
- If 2xx and not 204: response JSON
|
||||
- If 204 No Content: empty dict
|
||||
- If 4xx/5xx: {"error": True, "status_code": ..., "detail": "..."}
|
||||
(401 also carries "session_expired": True)
|
||||
"""
|
||||
if response.ok:
|
||||
if response.status_code == 204:
|
||||
return {}
|
||||
return response.json()
|
||||
|
||||
if response.status_code == 401:
|
||||
self._handle_session_expired()
|
||||
|
||||
# Non-OK response (4xx/5xx)
|
||||
try:
|
||||
error_body = response.json()
|
||||
@@ -74,11 +93,14 @@ class APIClient:
|
||||
except Exception:
|
||||
detail = response.text or f"HTTP {response.status_code}"
|
||||
|
||||
return {
|
||||
result = {
|
||||
"error": True,
|
||||
"status_code": response.status_code,
|
||||
"detail": detail
|
||||
}
|
||||
if response.status_code == 401:
|
||||
result["session_expired"] = True
|
||||
return result
|
||||
|
||||
def get(self, endpoint: str, params: dict | None = None) -> dict[str, Any]:
|
||||
"""GET request to API server."""
|
||||
|
||||
Reference in New Issue
Block a user