Add Google login functionality and update requirements
- Implement Google login endpoint with credential verification - Add GoogleLoginRequest schema for handling login requests - Update Settings class to include GOOGLE_CLIENT_ID - Add google-auth package to requirements
This commit is contained in:
parent
4fa2db2a3c
commit
08cc2bebbe
@ -13,6 +13,7 @@ class Settings(BaseSettings):
|
||||
SECRET_KEY: str = "change-me-to-a-random-secret-key"
|
||||
ALGORITHM: str = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 1440
|
||||
GOOGLE_CLIENT_ID: str = ""
|
||||
|
||||
@property
|
||||
def DATABASE_URL(self) -> str:
|
||||
|
||||
@ -1,10 +1,23 @@
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from google.oauth2 import id_token
|
||||
from google.auth.transport import requests as google_requests
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.models.user import User
|
||||
from app.models.user_profile import UserProfile
|
||||
from app.schemas.user import LoginRequest, LoginResponse, UserCreate, UserResponse
|
||||
from app.schemas.user import (
|
||||
GoogleLoginRequest,
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
UserCreate,
|
||||
UserResponse,
|
||||
)
|
||||
from app.security import create_access_token, hash_password, verify_password
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
@ -70,3 +83,82 @@ def register(data: UserCreate, db: Session = Depends(get_db)):
|
||||
|
||||
db.refresh(user)
|
||||
return user
|
||||
|
||||
|
||||
@router.post("/google-login", response_model=LoginResponse)
|
||||
def google_login(data: GoogleLoginRequest, db: Session = Depends(get_db)):
|
||||
try:
|
||||
idinfo = id_token.verify_oauth2_token(
|
||||
data.credential,
|
||||
google_requests.Request(),
|
||||
settings.GOOGLE_CLIENT_ID,
|
||||
)
|
||||
except Exception:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail={"message": "Kredensial Google tidak valid atau telah kedaluwarsa."},
|
||||
)
|
||||
|
||||
email = idinfo.get("email")
|
||||
name = idinfo.get("name", "")
|
||||
picture = idinfo.get("picture", "")
|
||||
|
||||
if not email:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail={"message": "Tidak dapat mengambil email dari akun Google."},
|
||||
)
|
||||
|
||||
user = db.query(User).options(selectinload(User.profile)).filter(
|
||||
User.email == email,
|
||||
User.deleted_at.is_(None),
|
||||
).first()
|
||||
|
||||
if not user:
|
||||
base_username = email.split("@")[0]
|
||||
username = base_username
|
||||
suffix = 1
|
||||
while db.query(User).filter(User.username == username).first():
|
||||
suffix += 1
|
||||
username = f"{base_username}{suffix}"
|
||||
|
||||
random_password = "".join(random.choices(string.ascii_letters + string.digits, k=32))
|
||||
|
||||
user = User(
|
||||
email=email,
|
||||
username=username,
|
||||
password=hash_password(random_password),
|
||||
email_verified_at=datetime.now(timezone.utc),
|
||||
status="ACTIVE",
|
||||
)
|
||||
db.add(user)
|
||||
db.flush()
|
||||
|
||||
profile = UserProfile(
|
||||
user_id=user.id,
|
||||
full_name=name,
|
||||
timezone="Asia/Jakarta",
|
||||
)
|
||||
db.add(profile)
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
else:
|
||||
if user.email_verified_at is None:
|
||||
user.email_verified_at = datetime.now(timezone.utc)
|
||||
if not user.profile:
|
||||
profile = UserProfile(
|
||||
user_id=user.id,
|
||||
full_name=name,
|
||||
timezone="Asia/Jakarta",
|
||||
)
|
||||
db.add(profile)
|
||||
elif user.profile.full_name != name:
|
||||
user.profile.full_name = name
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
|
||||
access_token = create_access_token({"sub": user.id})
|
||||
return LoginResponse(
|
||||
access_token=access_token,
|
||||
user=user,
|
||||
)
|
||||
|
||||
@ -56,3 +56,7 @@ class LoginResponse(BaseModel):
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
user: UserDetailResponse
|
||||
|
||||
|
||||
class GoogleLoginRequest(BaseModel):
|
||||
credential: str
|
||||
|
||||
@ -9,6 +9,7 @@ dnspython==2.8.0
|
||||
email-validator==2.3.0
|
||||
exceptiongroup==1.3.1
|
||||
fastapi==0.139.0
|
||||
google-auth==2.56.2
|
||||
fastapi-cli==0.0.29
|
||||
fastapi-cloud-cli==0.22.1
|
||||
fastar==0.11.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user