Complete admin package restructuring
This commit is contained in:
@ -0,0 +1,143 @@
|
||||
"""Authentication related views factory."""
|
||||
|
||||
# pyright: reportUnusedFunction=false
|
||||
import logging
|
||||
from pydantic import BaseModel
|
||||
from typing import Annotated
|
||||
from fastapi import APIRouter, Depends, Query, Request, Response, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlmodel import Session
|
||||
from starlette.datastructures import URL
|
||||
|
||||
from sshecret_admin.auth import (
|
||||
User,
|
||||
authenticate_user,
|
||||
create_access_token,
|
||||
create_refresh_token,
|
||||
)
|
||||
|
||||
from ..dependencies import FrontendDependencies
|
||||
from ..exceptions import RedirectException
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LoginError(BaseModel):
|
||||
"""Login error."""
|
||||
|
||||
title: str
|
||||
message: str
|
||||
|
||||
|
||||
def create_router(dependencies: FrontendDependencies) -> APIRouter:
|
||||
"""Create auth router."""
|
||||
|
||||
app = APIRouter()
|
||||
templates = dependencies.templates
|
||||
|
||||
@app.get("/login")
|
||||
async def get_login(
|
||||
request: Request,
|
||||
login_status: Annotated[bool, Depends(dependencies.get_login_status)],
|
||||
error_title: str | None = None,
|
||||
error_message: str | None = None,
|
||||
):
|
||||
"""Get index."""
|
||||
if login_status:
|
||||
return RedirectResponse("/dashboard")
|
||||
login_error: LoginError | None = None
|
||||
if error_title and error_message:
|
||||
login_error = LoginError(title=error_title, message=error_message)
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"login.html",
|
||||
{
|
||||
"page_title": "Login",
|
||||
"page_description": "Login page.",
|
||||
"login_error": login_error,
|
||||
},
|
||||
)
|
||||
|
||||
@app.post("/login")
|
||||
async def login_user(
|
||||
request: Request,
|
||||
response: Response,
|
||||
session: Annotated[Session, Depends(dependencies.get_db_session)],
|
||||
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
|
||||
next: Annotated[str, Query()] = "/dashboard",
|
||||
error_title: str | None = None,
|
||||
error_message: str | None = None,
|
||||
):
|
||||
"""Log in user."""
|
||||
if error_title and error_message:
|
||||
login_error = LoginError(title=error_title, message=error_message)
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"login.html",
|
||||
{
|
||||
"page_title": "Login",
|
||||
"page_description": "Login page.",
|
||||
"login_error": login_error,
|
||||
},
|
||||
)
|
||||
|
||||
user = authenticate_user(session, form_data.username, form_data.password)
|
||||
login_failed = RedirectException(
|
||||
to=URL("/login").include_query_params(
|
||||
error_title="Login Error", error_message="Invalid username or password"
|
||||
)
|
||||
)
|
||||
if not user:
|
||||
raise login_failed
|
||||
token_data: dict[str, str] = {"sub": user.username}
|
||||
access_token = create_access_token(dependencies.settings, data=token_data)
|
||||
refresh_token = create_refresh_token(dependencies.settings, data=token_data)
|
||||
response = RedirectResponse(url=next, status_code=status.HTTP_302_FOUND)
|
||||
response.set_cookie(
|
||||
"access_token",
|
||||
value=access_token,
|
||||
httponly=True,
|
||||
secure=False,
|
||||
samesite="strict",
|
||||
)
|
||||
response.set_cookie(
|
||||
"refresh_token",
|
||||
value=refresh_token,
|
||||
httponly=True,
|
||||
secure=False,
|
||||
samesite="strict",
|
||||
)
|
||||
return response
|
||||
|
||||
@app.get("/refresh")
|
||||
async def get_refresh_token(
|
||||
response: Response,
|
||||
user: Annotated[User, Depends(dependencies.get_user_from_refresh_token)],
|
||||
next: Annotated[str, Query()],
|
||||
):
|
||||
"""Refresh tokens.
|
||||
|
||||
We might as well refresh the long-lived one here.
|
||||
"""
|
||||
token_data: dict[str, str] = {"sub": user.username}
|
||||
access_token = create_access_token(dependencies.settings, data=token_data)
|
||||
refresh_token = create_refresh_token(dependencies.settings, data=token_data)
|
||||
response = RedirectResponse(url=next, status_code=status.HTTP_302_FOUND)
|
||||
response.set_cookie(
|
||||
"access_token",
|
||||
value=access_token,
|
||||
httponly=True,
|
||||
secure=False,
|
||||
samesite="strict",
|
||||
)
|
||||
response.set_cookie(
|
||||
"refresh_token",
|
||||
value=refresh_token,
|
||||
httponly=True,
|
||||
secure=False,
|
||||
samesite="strict",
|
||||
)
|
||||
return response
|
||||
|
||||
return app
|
||||
Reference in New Issue
Block a user