feat(auth): integrate Google OAuth2 and secure cookie management

- Configured CORS middleware to allow cross-origin requests from the frontend.
- Implemented Google OAuth2 login flow and post-auth frontend redirection.
- Managed secure HTTP-only cookies for access, refresh, and state tokens.
This commit is contained in:
2026-05-19 23:55:03 +08:00
parent 2b5e193046
commit c68d88b8c1
2 changed files with 67 additions and 11 deletions
+52 -11
View File
@@ -1,8 +1,13 @@
from ast import Is
import httpx
from fastapi import APIRouter, Depends, Request, HTTPException, BackgroundTasks
from fastapi.responses import RedirectResponse
import os
import secrets
import json
from urllib.parse import quote
from auth.deps import get_current_user
from app.db import SessionLocal
from app.models import User
@@ -19,6 +24,18 @@ GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth"
GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token"
GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo"
FRONTEND_URL = os.getenv("FRONTEND_URL", "http://localhost:3000")
ENV_MODE = os.getenv("ENV_MODE")
IS_PROD = ENV_MODE == "prod"
# 在文件顶部获取环境变量
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "60"))
REFRESH_TOKEN_EXPIRE_DAYS = int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", "7"))
# 统一转换为秒数(max_age 需要秒)
ACCESS_TOKEN_MAX_AGE = ACCESS_TOKEN_EXPIRE_MINUTES * 60
REFRESH_TOKEN_MAX_AGE = REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60
# 定义独立的后台任务函数,用于处理头像转存到 S3 的耗时操作
async def async_upload_avatar_task(google_avatar_url: str, user_id: str):
"""
@@ -159,17 +176,41 @@ async def auth_callback(request: Request, code: str, state: str, background_task
"sub": user.id,
"email": user.email,
})
return {
"access_token": jwt_token,
"refresh_token": refresh_token,
"token_type": "bearer",
# "user": {
# "email": user.email,
# "name": user.name,
# "avatar": get_image_url(user.avatar),
# }
}
response = RedirectResponse(url=f"{FRONTEND_URL}")
response.set_cookie(
key="access_token",
value=jwt_token,
httponly=True,
max_age=ACCESS_TOKEN_MAX_AGE,
samesite="lax",
secure=IS_PROD,
)
response.set_cookie(
key="refresh_token",
value=refresh_token,
httponly=True,
max_age=REFRESH_TOKEN_MAX_AGE,
samesite="lax",
secure=IS_PROD,
)
response.set_cookie(
key="user_info",
value=quote(json.dumps({
"email": user.email,
"name": user.name,
"avatar": user.avatar
})),
max_age=ACCESS_TOKEN_MAX_AGE,
httponly=False
)
response.delete_cookie("oauth_state")
return response
# @router.get("/me")
# def me(user = Depends(get_current_user)):