diff --git a/app/main.py b/app/main.py index 093e265..c0def1d 100644 --- a/app/main.py +++ b/app/main.py @@ -1,4 +1,6 @@ +import os from fastapi import FastAPI, Depends, HTTPException +from fastapi.middleware.cors import CORSMiddleware from strawberry import Schema from strawberry.fastapi import GraphQLRouter @@ -19,6 +21,19 @@ Base.metadata.create_all(bind=engine) # 创建 FastAPI 实例 app = FastAPI() +# 获取环境变量字符串,并转成列表 +origins_str = os.getenv("CORS_ORIGINS", "http://localhost:3000") +origins = [origin.strip() for origin in origins_str.split(",")] + +# 配置 CORS 中间件,允许前端访问 +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + # 组装 GraphQL Schema schema = Schema(query=Query, mutation=Mutation) diff --git a/auth/oauth/google.py b/auth/oauth/google.py index 8037614..ed18a31 100644 --- a/auth/oauth/google.py +++ b/auth/oauth/google.py @@ -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)):