Redirecting deep links after login
This commit is contained in:
1 parent
a7fb902611
commit
25fccd617f
5 files changed
+118
-7
No files matched your search
+30
-5
@@ -1,4 +1,4 @@
|
||||
from fastapi import APIRouter, Depends, Form, HTTPException, Request, status
|
||||
from fastapi import APIRouter, Depends, Form, HTTPException, Query, Request, status
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse, Response
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -14,6 +14,21 @@ from app.web.templates import templates
|
||||
router = APIRouter(include_in_schema=False)
|
||||
|
||||
|
||||
def _safe_next(next_url: str) -> str:
|
||||
"""Return next_url only if it's a safe same-site path, else "/".
|
||||
|
||||
Guards against open-redirect: rejects absolute URLs and protocol-relative
|
||||
("//host", "/\\host") targets, and never bounces back to the auth pages.
|
||||
"""
|
||||
if (
|
||||
next_url.startswith("/")
|
||||
and not next_url.startswith(("//", "/\\"))
|
||||
and not next_url.startswith(("/login", "/logout"))
|
||||
):
|
||||
return next_url
|
||||
return "/"
|
||||
|
||||
|
||||
def _set_auth_cookie(response: Response, access_token: str) -> None:
|
||||
response.set_cookie(
|
||||
key=settings.cookie_name,
|
||||
@@ -35,9 +50,11 @@ async def dashboard(
|
||||
|
||||
|
||||
@router.get("/login", response_class=HTMLResponse)
|
||||
async def login_page(request: Request):
|
||||
async def login_page(request: Request, next_url: str = Query("", alias="next")):
|
||||
return templates.TemplateResponse(
|
||||
request, "login.html", {"ldap_enabled": settings.ldap_enabled}
|
||||
request,
|
||||
"login.html",
|
||||
{"ldap_enabled": settings.ldap_enabled, "next_url": _safe_next(next_url)},
|
||||
)
|
||||
|
||||
|
||||
@@ -46,6 +63,7 @@ async def login_submit(
|
||||
request: Request,
|
||||
email: str = Form(...),
|
||||
password: str = Form(...),
|
||||
next_url: str = Form("", alias="next"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
user = await user_crud.authenticate(db, email, password)
|
||||
@@ -57,11 +75,14 @@ async def login_submit(
|
||||
"local_error": "Incorrect email or password",
|
||||
"email": email,
|
||||
"ldap_enabled": settings.ldap_enabled,
|
||||
"next_url": _safe_next(next_url),
|
||||
},
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
)
|
||||
access, _ = await issue_token_pair(db, user)
|
||||
response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER)
|
||||
response = RedirectResponse(
|
||||
url=_safe_next(next_url), status_code=status.HTTP_303_SEE_OTHER
|
||||
)
|
||||
_set_auth_cookie(response, access)
|
||||
return response
|
||||
|
||||
@@ -71,6 +92,7 @@ async def login_ldap_submit(
|
||||
request: Request,
|
||||
username: str = Form(...),
|
||||
password: str = Form(...),
|
||||
next_url: str = Form("", alias="next"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
if not settings.ldap_enabled:
|
||||
@@ -84,11 +106,14 @@ async def login_ldap_submit(
|
||||
"ldap_error": "Incorrect username or password",
|
||||
"username": username,
|
||||
"ldap_enabled": True,
|
||||
"next_url": _safe_next(next_url),
|
||||
},
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
)
|
||||
access, _ = await issue_token_pair(db, user)
|
||||
response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER)
|
||||
response = RedirectResponse(
|
||||
url=_safe_next(next_url), status_code=status.HTTP_303_SEE_OTHER
|
||||
)
|
||||
_set_auth_cookie(response, access)
|
||||
return response
|
||||
|
||||
|
||||
Reference in new issue
Block a user