import uuid from collections.abc import AsyncGenerator from fastapi import Depends, Request from fastapi_users import BaseUserManager, FastAPIUsers, UUIDIDMixin from fastapi_users.authentication import ( AuthenticationBackend, BearerTransport, JWTStrategy, ) from fastapi_users.db import SQLAlchemyUserDatabase from sqlalchemy.ext.asyncio import AsyncSession from app.auth.email import send_email from app.config import settings from app.db import get_async_session from app.models.user import User JWT_LIFETIME_SECONDS = 60 * 60 * 24 * 7 # 7 days async def get_user_db( session: AsyncSession = Depends(get_async_session), ) -> AsyncGenerator[SQLAlchemyUserDatabase, None]: yield SQLAlchemyUserDatabase(session, User) class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]): reset_password_token_secret = settings.reset_password_secret verification_token_secret = settings.verification_token_secret async def on_after_forgot_password( self, user: User, token: str, request: Request | None = None ) -> None: reset_url = f"{settings.frontend_origin}/reset-password?token={token}" await send_email( to=user.email, subject="Passwort zurücksetzen — DungeonsDragons", body=( f"Hallo {user.name},\n\n" f"klicke auf den folgenden Link, um dein Passwort zurückzusetzen:\n{reset_url}\n\n" "Falls du das nicht angefordert hast, ignoriere diese E-Mail." ), ) async def get_user_manager( user_db: SQLAlchemyUserDatabase = Depends(get_user_db), ) -> AsyncGenerator[UserManager, None]: yield UserManager(user_db) bearer_transport = BearerTransport(tokenUrl="auth/jwt/login") def get_jwt_strategy() -> JWTStrategy: return JWTStrategy(secret=settings.jwt_secret, lifetime_seconds=JWT_LIFETIME_SECONDS) auth_backend = AuthenticationBackend( name="jwt", transport=bearer_transport, get_strategy=get_jwt_strategy, ) fastapi_users = FastAPIUsers[User, uuid.UUID](get_user_manager, [auth_backend]) current_active_user = fastapi_users.current_user(active=True)