feat: first commit, auth
This commit is contained in:
75
routes/auth.py
Normal file
75
routes/auth.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.secrets import hash_password, hash_refresh_token, verify_password
|
||||
from db.session import get_db
|
||||
from repositories.sessions import SessionsRepository
|
||||
from repositories.users import UserRepository
|
||||
from schemas.login import UserLogin, UserLoginData, UserTokens
|
||||
from schemas.providers import ProvidersType
|
||||
from schemas.registration import UserRegistration
|
||||
from schemas.user import UserInfo
|
||||
from services.sessions import refresh_token_rotation
|
||||
from services.users import authorize_user
|
||||
|
||||
router = APIRouter(prefix="/auth")
|
||||
|
||||
|
||||
@router.post("/signup")
|
||||
async def signup(req: UserRegistration, session: AsyncSession = Depends(get_db)):
|
||||
users_repo = UserRepository(session)
|
||||
|
||||
if req.provider == "credentials":
|
||||
if not req.username or not req.password:
|
||||
raise HTTPException(status_code=400, detail="Username or password is not provided")
|
||||
user = await users_repo.get_user_by_username(req.username)
|
||||
if user:
|
||||
raise HTTPException(status_code=409, detail="User already exists")
|
||||
|
||||
password_hash = hash_password(req.password)
|
||||
user = await users_repo.create(username=req.username, hashed_password=password_hash)
|
||||
return JSONResponse(
|
||||
UserInfo(username=user.username, telegram_id=user.telegram_id).model_dump(),
|
||||
status_code=201,
|
||||
)
|
||||
raise HTTPException(status_code=400, detail="Unsupported provider")
|
||||
|
||||
|
||||
@router.post("/login", response_model=UserLogin)
|
||||
async def login(req: UserLoginData, session: AsyncSession = Depends(get_db)):
|
||||
users_repo = UserRepository(session)
|
||||
sessions_repo = SessionsRepository(session)
|
||||
if req.provider == "credentials":
|
||||
if not req.username or not req.password:
|
||||
raise HTTPException(status_code=400, detail="Username or password is not provided.")
|
||||
|
||||
user = await users_repo.get_user_by_username(req.username)
|
||||
if not user:
|
||||
raise HTTPException(status_code=401, detail="User doesn't exist.")
|
||||
|
||||
if not verify_password(user.hashed_password, req.password):
|
||||
raise HTTPException(status_code=401, detail="Invalid password")
|
||||
|
||||
data = await authorize_user(sessions_repo, user, req.provider)
|
||||
return data
|
||||
|
||||
if req.provider == "telegram":
|
||||
raise HTTPException(status_code=503, detail="Under development :)")
|
||||
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="Unknown provider.")
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=UserTokens)
|
||||
async def refresh(refresh_token: str, iss: ProvidersType, session: AsyncSession = Depends(get_db)):
|
||||
sessions_repo = SessionsRepository(session)
|
||||
|
||||
token_hash = hash_refresh_token(refresh_token)
|
||||
token_entry = await sessions_repo.get_session_by_hash(token_hash)
|
||||
|
||||
if not token_entry:
|
||||
raise HTTPException(status_code=401, detail="Refresh token is invalid.")
|
||||
|
||||
key_pair = await refresh_token_rotation(sessions_repo, token_entry, iss)
|
||||
return UserTokens(access_token=key_pair.access_token, refresh_token=key_pair.refresh_token)
|
||||
Reference in New Issue
Block a user