Redirect to login instead of raw 401 JSON on expired session
A page tab left open past COOKIE_MAX_AGE and then reloaded hit
require_user/require_admin raising before the route body ever ran,
so there was nowhere to catch it and show something friendlier - the
browser just rendered {"detail": "Unauthorized"}. A global exception
handler now redirects GET page loads (never /api/* calls, whose JS
callers parse and handle the JSON error themselves, and never
POST/PUT/DELETE, so a failed login or CSRF check still reports its
own error instead of silently bouncing) with a 401/403 back to /.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+18
@@ -17,6 +17,7 @@ from markupsafe import Markup, escape
|
||||
from sqlalchemy import delete, select, text, update
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.responses import HTMLResponse as _HR
|
||||
from starlette.exceptions import HTTPException as _StarletteHTTPException
|
||||
|
||||
import urllib.request as _urllib_request
|
||||
import urllib.parse as _urllib_parse
|
||||
@@ -888,6 +889,23 @@ async def _process_callback_query(cq: dict):
|
||||
app = FastAPI(title="MONT - инфрастуктурный полигон", docs_url=None, redoc_url=None, openapi_url=None)
|
||||
|
||||
|
||||
@app.exception_handler(_StarletteHTTPException)
|
||||
async def _auth_redirect_handler(request: Request, exc: _StarletteHTTPException):
|
||||
"""A session that expired while a page tab sat open used to surface as
|
||||
a raw {"detail": "Unauthorized"} JSON blob on reload - require_user/
|
||||
require_admin raise before the page route body ever runs, so there was
|
||||
nowhere in those routes to catch it and show something friendlier.
|
||||
Redirect browser page loads (never /api/* calls, whose JS callers parse
|
||||
the JSON body and show their own error) back to the login page instead."""
|
||||
if (
|
||||
exc.status_code in (401, 403)
|
||||
and request.method == "GET"
|
||||
and not request.url.path.startswith("/api/")
|
||||
):
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail}, headers=exc.headers)
|
||||
|
||||
|
||||
@app.get("/admin/access-request/{req_id}/decide")
|
||||
def access_request_decide_confirm(req_id: str, action: str, token: str, db: Session = Depends(get_db)):
|
||||
"""GET only renders a confirmation page - it must never mutate state,
|
||||
|
||||
Reference in New Issue
Block a user