58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
from fastapi import APIRouter, Depends, Response, HTTPException, Request
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
|
|
from app.api.deps import db_session, get_current_user
|
|
from app.core.config import settings
|
|
from app.core.security import (
|
|
verify_password, create_session_token, new_csrf_token,
|
|
SESSION_COOKIE, CSRF_COOKIE
|
|
)
|
|
from app.models.user import User
|
|
from app.schemas.user import LoginIn, UserOut
|
|
|
|
router = APIRouter()
|
|
|
|
@router.post("/login")
|
|
async def login(payload: LoginIn, response: Response, session: AsyncSession = Depends(db_session)):
|
|
res = await session.execute(select(User).where(User.email == payload.email))
|
|
user = res.scalar_one_or_none()
|
|
if not user or not verify_password(payload.password, user.password_hash):
|
|
raise HTTPException(status_code=401, detail="Bad credentials")
|
|
if not user.is_active:
|
|
raise HTTPException(status_code=403, detail="Inactive")
|
|
|
|
token = create_session_token(user.id)
|
|
csrf = new_csrf_token()
|
|
|
|
response.set_cookie(
|
|
key=SESSION_COOKIE,
|
|
value=token,
|
|
httponly=True,
|
|
secure=settings.COOKIE_SECURE,
|
|
samesite=settings.COOKIE_SAMESITE,
|
|
max_age=60 * 60 * 24 * 7,
|
|
path="/",
|
|
)
|
|
# CSRF token czytelny dla JS (nie httponly)
|
|
response.set_cookie(
|
|
key=CSRF_COOKIE,
|
|
value=csrf,
|
|
httponly=False,
|
|
secure=settings.COOKIE_SECURE,
|
|
samesite=settings.COOKIE_SAMESITE,
|
|
max_age=60 * 60 * 24 * 7,
|
|
path="/",
|
|
)
|
|
return {"ok": True}
|
|
|
|
@router.post("/logout")
|
|
async def logout(response: Response):
|
|
response.delete_cookie(SESSION_COOKIE, path="/")
|
|
response.delete_cookie(CSRF_COOKIE, path="/")
|
|
return {"ok": True}
|
|
|
|
@router.get("/me", response_model=UserOut)
|
|
async def me(user: User = Depends(get_current_user)):
|
|
return UserOut(id=user.id, email=user.email, role=user.role)
|