mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init new auth
This commit is contained in:
parent
f838a8512c
commit
1708b36818
34 changed files with 1853 additions and 3613 deletions
|
|
@ -1,11 +1,14 @@
|
|||
from datetime import timedelta
|
||||
from typing import Literal, Optional
|
||||
from fastapi import Depends, APIRouter, HTTPException, Response, status, Request
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from sqlmodel import Session
|
||||
from src.db.users import UserRead
|
||||
from src.db.users import AnonymousUser, PublicUser, UserRead
|
||||
from src.core.events.database import get_db_session
|
||||
from config.config import get_learnhouse_config
|
||||
from src.security.auth import AuthJWT, authenticate_user
|
||||
from src.security.auth import AuthJWT, authenticate_user, get_current_user
|
||||
from src.services.auth.utils import get_google_user_info, signWithGoogle
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
|
@ -74,6 +77,58 @@ async def login(
|
|||
return result
|
||||
|
||||
|
||||
class ThirdPartyLogin(BaseModel):
|
||||
email: EmailStr
|
||||
provider: Literal["google"]
|
||||
access_token: str
|
||||
|
||||
|
||||
@router.post("/oauth")
|
||||
async def third_party_login(
|
||||
request: Request,
|
||||
response: Response,
|
||||
body: ThirdPartyLogin,
|
||||
org_id: Optional[int] = None,
|
||||
current_user: AnonymousUser = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
Authorize: AuthJWT = Depends(),
|
||||
):
|
||||
# Google
|
||||
if body.provider == "google":
|
||||
|
||||
user = await signWithGoogle(
|
||||
request, body.access_token, body.email, org_id, current_user, db_session
|
||||
)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect Email or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
access_token = Authorize.create_access_token(subject=user.email)
|
||||
refresh_token = Authorize.create_refresh_token(subject=user.email)
|
||||
Authorize.set_refresh_cookies(refresh_token)
|
||||
|
||||
# set cookies using fastapi
|
||||
response.set_cookie(
|
||||
key="access_token_cookie",
|
||||
value=access_token,
|
||||
httponly=False,
|
||||
domain=get_learnhouse_config().hosting_config.cookie_config.domain,
|
||||
expires=int(timedelta(hours=8).total_seconds()),
|
||||
)
|
||||
|
||||
user = UserRead.model_validate(user)
|
||||
|
||||
result = {
|
||||
"user": user,
|
||||
"tokens": {"access_token": access_token, "refresh_token": refresh_token},
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
@router.delete("/logout")
|
||||
def logout(Authorize: AuthJWT = Depends()):
|
||||
"""
|
||||
|
|
|
|||
70
apps/api/src/services/auth/utils.py
Normal file
70
apps/api/src/services/auth/utils.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import random
|
||||
from typing import Optional
|
||||
from fastapi import Depends, HTTPException, Request
|
||||
import httpx
|
||||
from sqlmodel import Session, select
|
||||
from src.core.events.database import get_db_session
|
||||
from src.db.users import User, UserCreate, UserRead
|
||||
from src.security.auth import get_current_user
|
||||
from src.services.users.users import create_user, create_user_without_org
|
||||
|
||||
|
||||
async def get_google_user_info(access_token: str):
|
||||
url = "https://www.googleapis.com/oauth2/v3/userinfo"
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise HTTPException(
|
||||
status_code=response.status_code,
|
||||
detail="Failed to fetch user info from Google",
|
||||
)
|
||||
|
||||
return response.json()
|
||||
|
||||
|
||||
async def signWithGoogle(
|
||||
request: Request,
|
||||
access_token: str,
|
||||
email: str,
|
||||
org_id: Optional[int] = None,
|
||||
current_user=Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
# Google
|
||||
google_user = await get_google_user_info(access_token)
|
||||
|
||||
user = db_session.exec(
|
||||
select(User).where(User.email == google_user["email"])
|
||||
).first()
|
||||
|
||||
if not user:
|
||||
username = (
|
||||
google_user["given_name"]
|
||||
+ google_user["family_name"]
|
||||
+ str(random.randint(10, 99))
|
||||
)
|
||||
user_object = UserCreate(
|
||||
email=google_user["email"],
|
||||
username=username,
|
||||
password="",
|
||||
first_name=google_user["given_name"],
|
||||
last_name=google_user["family_name"],
|
||||
avatar_image=google_user["picture"],
|
||||
)
|
||||
|
||||
if org_id is not None:
|
||||
user = await create_user(
|
||||
request, db_session, current_user, user_object, org_id
|
||||
)
|
||||
|
||||
return user
|
||||
else:
|
||||
user = await create_user_without_org(
|
||||
request, db_session, current_user, user_object
|
||||
)
|
||||
|
||||
return user
|
||||
|
||||
return UserRead.model_validate(user)
|
||||
|
|
@ -17,7 +17,7 @@ def send_account_creation_email(
|
|||
<body>
|
||||
<p>Hello {user.username}</p>
|
||||
<p>Welcome to LearnHouse! , get started by creating your own organization or join a one.</p>
|
||||
<p>Need some help to get started ? <a href="https://learn.learnhouse.io">LearnHouse Academy</a></p>
|
||||
<p>Need some help to get started ? <a href="https://university.learnhouse.io">LearnHouse Academy</a></p>
|
||||
</body>
|
||||
</html>
|
||||
""",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue