Mark-Lasfar
commited on
Commit
·
09451d2
1
Parent(s):
fb023ba
Update backend and server frontend for OAuth JSON response, client-side navigation, and add .gitignore
Browse files- api/auth.py +45 -42
- main.py +3 -5
api/auth.py
CHANGED
|
@@ -3,12 +3,11 @@
|
|
| 3 |
|
| 4 |
from fastapi_users import FastAPIUsers
|
| 5 |
from fastapi_users.authentication import CookieTransport, JWTStrategy, AuthenticationBackend
|
| 6 |
-
from fastapi_users.router.oauth import get_oauth_router
|
| 7 |
from httpx_oauth.clients.google import GoogleOAuth2
|
| 8 |
from httpx_oauth.clients.github import GitHubOAuth2
|
| 9 |
from fastapi_users.manager import BaseUserManager, IntegerIDMixin
|
| 10 |
from fastapi import Depends, Request, FastAPI, Response
|
| 11 |
-
from fastapi.responses import
|
| 12 |
from sqlalchemy.ext.asyncio import AsyncSession
|
| 13 |
from sqlalchemy import select
|
| 14 |
from fastapi_users.models import UP
|
|
@@ -55,8 +54,10 @@ GITHUB_REDIRECT_URL = os.getenv("GITHUB_REDIRECT_URL", "https://mgzon-mgzon-app.
|
|
| 55 |
|
| 56 |
google_oauth_client = GoogleOAuth2(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
|
| 57 |
github_oauth_client = GitHubOAuth2(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET)
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
# مدير المستخدمين
|
| 60 |
class UserManager(IntegerIDMixin, BaseUserManager[User, int]):
|
| 61 |
reset_password_token_secret = SECRET
|
| 62 |
verification_token_secret = SECRET
|
|
@@ -144,27 +145,6 @@ class UserManager(IntegerIDMixin, BaseUserManager[User, int]):
|
|
| 144 |
async def get_user_manager(user_db: CustomSQLAlchemyUserDatabase = Depends(get_user_db)):
|
| 145 |
yield UserManager(user_db)
|
| 146 |
|
| 147 |
-
# تعديل الـ OAuth Routers لتضمين redirect مخصص
|
| 148 |
-
google_oauth_router = get_oauth_router(
|
| 149 |
-
google_oauth_client,
|
| 150 |
-
auth_backend,
|
| 151 |
-
get_user_manager,
|
| 152 |
-
state_secret=SECRET,
|
| 153 |
-
associate_by_email=True,
|
| 154 |
-
redirect_url=GOOGLE_REDIRECT_URL,
|
| 155 |
-
)
|
| 156 |
-
|
| 157 |
-
github_oauth_client._access_token_url = "https://github.com/login/oauth/access_token"
|
| 158 |
-
github_oauth_client._access_token_params = {"headers": {"Accept": "application/json"}}
|
| 159 |
-
github_oauth_router = get_oauth_router(
|
| 160 |
-
github_oauth_client,
|
| 161 |
-
auth_backend,
|
| 162 |
-
get_user_manager,
|
| 163 |
-
state_secret=SECRET,
|
| 164 |
-
associate_by_email=True,
|
| 165 |
-
redirect_url=GITHUB_REDIRECT_URL,
|
| 166 |
-
)
|
| 167 |
-
|
| 168 |
fastapi_users = FastAPIUsers[User, int](
|
| 169 |
get_user_db,
|
| 170 |
[auth_backend],
|
|
@@ -172,9 +152,40 @@ fastapi_users = FastAPIUsers[User, int](
|
|
| 172 |
|
| 173 |
current_active_user = fastapi_users.current_user(active=True, optional=True)
|
| 174 |
|
| 175 |
-
# إضافة
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
-
# تعديل الـ OAuth Callback لـ Google
|
| 178 |
async def custom_oauth_callback(
|
| 179 |
code: str,
|
| 180 |
user_manager: UserManager = Depends(get_user_manager),
|
|
@@ -184,12 +195,10 @@ async def custom_oauth_callback(
|
|
| 184 |
):
|
| 185 |
logger.debug(f"Processing Google callback with code: {code}")
|
| 186 |
try:
|
| 187 |
-
# جلب access token من Google
|
| 188 |
token_data = await oauth_client.get_access_token(code, redirect_url)
|
| 189 |
access_token = token_data["access_token"]
|
| 190 |
user_info = await oauth_client.get_user_info(access_token)
|
| 191 |
|
| 192 |
-
# استدعاء oauth_callback من UserManager
|
| 193 |
user = await user_manager.oauth_callback(
|
| 194 |
oauth_name="google",
|
| 195 |
access_token=access_token,
|
|
@@ -201,22 +210,19 @@ async def custom_oauth_callback(
|
|
| 201 |
is_verified_by_default=True,
|
| 202 |
)
|
| 203 |
|
| 204 |
-
# إنشاء JWT token
|
| 205 |
jwt_strategy = get_jwt_strategy()
|
| 206 |
token = await jwt_strategy.write(user)
|
| 207 |
|
| 208 |
-
# تعيين الـ token في الكوكيز
|
| 209 |
cookie_transport.set_cookie(response, token)
|
| 210 |
|
| 211 |
-
# رجع JSON بدل redirect
|
| 212 |
return JSONResponse(content={
|
| 213 |
"message": "Google login successful",
|
| 214 |
"access_token": token
|
| 215 |
}, status_code=200)
|
| 216 |
except Exception as e:
|
| 217 |
logger.error(f"Error in Google OAuth callback: {str(e)}")
|
| 218 |
-
|
| 219 |
-
|
| 220 |
async def custom_github_oauth_callback(
|
| 221 |
code: str,
|
| 222 |
user_manager: UserManager = Depends(get_user_manager),
|
|
@@ -226,12 +232,10 @@ async def custom_github_oauth_callback(
|
|
| 226 |
):
|
| 227 |
logger.debug(f"Processing GitHub callback with code: {code}")
|
| 228 |
try:
|
| 229 |
-
# جلب access token من GitHub
|
| 230 |
token_data = await oauth_client.get_access_token(code, redirect_url)
|
| 231 |
access_token = token_data["access_token"]
|
| 232 |
user_info = await oauth_client.get_user_info(access_token)
|
| 233 |
|
| 234 |
-
# استدعاء oauth_callback من UserManager
|
| 235 |
user = await user_manager.oauth_callback(
|
| 236 |
oauth_name="github",
|
| 237 |
access_token=access_token,
|
|
@@ -243,22 +247,20 @@ async def custom_github_oauth_callback(
|
|
| 243 |
is_verified_by_default=True,
|
| 244 |
)
|
| 245 |
|
| 246 |
-
# إنشاء JWT token
|
| 247 |
jwt_strategy = get_jwt_strategy()
|
| 248 |
token = await jwt_strategy.write(user)
|
| 249 |
|
| 250 |
-
# تعيين الـ token في الكوكيز
|
| 251 |
cookie_transport.set_cookie(response, token)
|
| 252 |
|
| 253 |
-
# رجع JSON بدل redirect
|
| 254 |
return JSONResponse(content={
|
| 255 |
"message": "GitHub login successful",
|
| 256 |
"access_token": token
|
| 257 |
}, status_code=200)
|
| 258 |
except Exception as e:
|
| 259 |
logger.error(f"Error in GitHub OAuth callback: {str(e)}")
|
| 260 |
-
|
| 261 |
-
|
|
|
|
| 262 |
def get_auth_router(app: FastAPI):
|
| 263 |
app.include_router(fastapi_users.get_auth_router(auth_backend), prefix="/auth/jwt", tags=["auth"])
|
| 264 |
app.include_router(fastapi_users.get_register_router(UserRead, UserCreate), prefix="/auth", tags=["auth"])
|
|
@@ -266,7 +268,8 @@ def get_auth_router(app: FastAPI):
|
|
| 266 |
app.include_router(fastapi_users.get_verify_router(UserRead), prefix="/auth", tags=["auth"])
|
| 267 |
app.include_router(fastapi_users.get_users_router(UserRead, UserUpdate), prefix="/users", tags=["users"])
|
| 268 |
|
| 269 |
-
# إضافة الـ custom callback
|
|
|
|
| 270 |
app.get("/auth/google/callback")(custom_oauth_callback)
|
|
|
|
| 271 |
app.get("/auth/github/callback")(custom_github_oauth_callback)
|
| 272 |
-
|
|
|
|
| 3 |
|
| 4 |
from fastapi_users import FastAPIUsers
|
| 5 |
from fastapi_users.authentication import CookieTransport, JWTStrategy, AuthenticationBackend
|
|
|
|
| 6 |
from httpx_oauth.clients.google import GoogleOAuth2
|
| 7 |
from httpx_oauth.clients.github import GitHubOAuth2
|
| 8 |
from fastapi_users.manager import BaseUserManager, IntegerIDMixin
|
| 9 |
from fastapi import Depends, Request, FastAPI, Response
|
| 10 |
+
from fastapi.responses import JSONResponse
|
| 11 |
from sqlalchemy.ext.asyncio import AsyncSession
|
| 12 |
from sqlalchemy import select
|
| 13 |
from fastapi_users.models import UP
|
|
|
|
| 54 |
|
| 55 |
google_oauth_client = GoogleOAuth2(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
|
| 56 |
github_oauth_client = GitHubOAuth2(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET)
|
| 57 |
+
github_oauth_client._access_token_url = "https://github.com/login/oauth/access_token"
|
| 58 |
+
github_oauth_client._access_token_params = {"headers": {"Accept": "application/json"}}
|
| 59 |
|
| 60 |
+
# مدير المستخدمين (بدون تغيير)
|
| 61 |
class UserManager(IntegerIDMixin, BaseUserManager[User, int]):
|
| 62 |
reset_password_token_secret = SECRET
|
| 63 |
verification_token_secret = SECRET
|
|
|
|
| 145 |
async def get_user_manager(user_db: CustomSQLAlchemyUserDatabase = Depends(get_user_db)):
|
| 146 |
yield UserManager(user_db)
|
| 147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
fastapi_users = FastAPIUsers[User, int](
|
| 149 |
get_user_db,
|
| 150 |
[auth_backend],
|
|
|
|
| 152 |
|
| 153 |
current_active_user = fastapi_users.current_user(active=True, optional=True)
|
| 154 |
|
| 155 |
+
# --- إضافة custom authorize endpoints (يرجع JSON مع authorization_url) ---
|
| 156 |
+
|
| 157 |
+
# Custom Google Authorize
|
| 158 |
+
async def custom_google_authorize(
|
| 159 |
+
state: Optional[str] = None,
|
| 160 |
+
oauth_client=Depends(lambda: google_oauth_client),
|
| 161 |
+
):
|
| 162 |
+
logger.debug("Generating Google authorization URL")
|
| 163 |
+
state_data = secrets.token_urlsafe(32) if state is None else state
|
| 164 |
+
authorization_url = await oauth_client.get_authorization_url(
|
| 165 |
+
redirect_uri=GOOGLE_REDIRECT_URL,
|
| 166 |
+
state=state_data,
|
| 167 |
+
)
|
| 168 |
+
return JSONResponse(content={
|
| 169 |
+
"authorization_url": authorization_url
|
| 170 |
+
}, status_code=200)
|
| 171 |
+
|
| 172 |
+
# Custom GitHub Authorize
|
| 173 |
+
async def custom_github_authorize(
|
| 174 |
+
state: Optional[str] = None,
|
| 175 |
+
oauth_client=Depends(lambda: github_oauth_client),
|
| 176 |
+
):
|
| 177 |
+
logger.debug("Generating GitHub authorization URL")
|
| 178 |
+
state_data = secrets.token_urlsafe(32) if state is None else state
|
| 179 |
+
authorization_url = await oauth_client.get_authorization_url(
|
| 180 |
+
redirect_uri=GITHUB_REDIRECT_URL,
|
| 181 |
+
state=state_data,
|
| 182 |
+
)
|
| 183 |
+
return JSONResponse(content={
|
| 184 |
+
"authorization_url": authorization_url
|
| 185 |
+
}, status_code=200)
|
| 186 |
+
|
| 187 |
+
# --- Custom Callback endpoints (بدون تغيير، يرجع JSON مع token) ---
|
| 188 |
|
|
|
|
| 189 |
async def custom_oauth_callback(
|
| 190 |
code: str,
|
| 191 |
user_manager: UserManager = Depends(get_user_manager),
|
|
|
|
| 195 |
):
|
| 196 |
logger.debug(f"Processing Google callback with code: {code}")
|
| 197 |
try:
|
|
|
|
| 198 |
token_data = await oauth_client.get_access_token(code, redirect_url)
|
| 199 |
access_token = token_data["access_token"]
|
| 200 |
user_info = await oauth_client.get_user_info(access_token)
|
| 201 |
|
|
|
|
| 202 |
user = await user_manager.oauth_callback(
|
| 203 |
oauth_name="google",
|
| 204 |
access_token=access_token,
|
|
|
|
| 210 |
is_verified_by_default=True,
|
| 211 |
)
|
| 212 |
|
|
|
|
| 213 |
jwt_strategy = get_jwt_strategy()
|
| 214 |
token = await jwt_strategy.write(user)
|
| 215 |
|
|
|
|
| 216 |
cookie_transport.set_cookie(response, token)
|
| 217 |
|
|
|
|
| 218 |
return JSONResponse(content={
|
| 219 |
"message": "Google login successful",
|
| 220 |
"access_token": token
|
| 221 |
}, status_code=200)
|
| 222 |
except Exception as e:
|
| 223 |
logger.error(f"Error in Google OAuth callback: {str(e)}")
|
| 224 |
+
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
| 225 |
+
|
| 226 |
async def custom_github_oauth_callback(
|
| 227 |
code: str,
|
| 228 |
user_manager: UserManager = Depends(get_user_manager),
|
|
|
|
| 232 |
):
|
| 233 |
logger.debug(f"Processing GitHub callback with code: {code}")
|
| 234 |
try:
|
|
|
|
| 235 |
token_data = await oauth_client.get_access_token(code, redirect_url)
|
| 236 |
access_token = token_data["access_token"]
|
| 237 |
user_info = await oauth_client.get_user_info(access_token)
|
| 238 |
|
|
|
|
| 239 |
user = await user_manager.oauth_callback(
|
| 240 |
oauth_name="github",
|
| 241 |
access_token=access_token,
|
|
|
|
| 247 |
is_verified_by_default=True,
|
| 248 |
)
|
| 249 |
|
|
|
|
| 250 |
jwt_strategy = get_jwt_strategy()
|
| 251 |
token = await jwt_strategy.write(user)
|
| 252 |
|
|
|
|
| 253 |
cookie_transport.set_cookie(response, token)
|
| 254 |
|
|
|
|
| 255 |
return JSONResponse(content={
|
| 256 |
"message": "GitHub login successful",
|
| 257 |
"access_token": token
|
| 258 |
}, status_code=200)
|
| 259 |
except Exception as e:
|
| 260 |
logger.error(f"Error in GitHub OAuth callback: {str(e)}")
|
| 261 |
+
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
| 262 |
+
|
| 263 |
+
# تضمين الراوترات داخل التطبيق (بدون OAuth routers هنا، هنضيفهم يدويًا)
|
| 264 |
def get_auth_router(app: FastAPI):
|
| 265 |
app.include_router(fastapi_users.get_auth_router(auth_backend), prefix="/auth/jwt", tags=["auth"])
|
| 266 |
app.include_router(fastapi_users.get_register_router(UserRead, UserCreate), prefix="/auth", tags=["auth"])
|
|
|
|
| 268 |
app.include_router(fastapi_users.get_verify_router(UserRead), prefix="/auth", tags=["auth"])
|
| 269 |
app.include_router(fastapi_users.get_users_router(UserRead, UserUpdate), prefix="/users", tags=["users"])
|
| 270 |
|
| 271 |
+
# إضافة الـ custom OAuth endpoints يدويًا (authorize + callback)
|
| 272 |
+
app.get("/auth/google/authorize")(custom_google_authorize)
|
| 273 |
app.get("/auth/google/callback")(custom_oauth_callback)
|
| 274 |
+
app.get("/auth/github/authorize")(custom_github_authorize)
|
| 275 |
app.get("/auth/github/callback")(custom_github_oauth_callback)
|
|
|
main.py
CHANGED
|
@@ -13,7 +13,7 @@ from starlette.middleware.sessions import SessionMiddleware
|
|
| 13 |
from fastapi.openapi.docs import get_swagger_ui_html
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
from api.endpoints import router as api_router
|
| 16 |
-
from api.auth import fastapi_users, auth_backend, current_active_user, get_auth_router
|
| 17 |
from api.database import User, Conversation, get_db, init_db
|
| 18 |
from api.models import UserRead, UserCreate, UserUpdate
|
| 19 |
from motor.motor_asyncio import AsyncIOMotorClient
|
|
@@ -141,10 +141,8 @@ logger.debug("CORS middleware configured with allowed origins")
|
|
| 141 |
|
| 142 |
# Include routers
|
| 143 |
app.include_router(api_router)
|
| 144 |
-
app
|
| 145 |
-
|
| 146 |
-
get_auth_router(app) # الراوترات الأخرى (JWT, register, etc.)
|
| 147 |
-
logger.debug("API, Google OAuth, GitHub OAuth, and auth routers included")
|
| 148 |
|
| 149 |
# Add logout endpoint
|
| 150 |
@app.post("/logout")
|
|
|
|
| 13 |
from fastapi.openapi.docs import get_swagger_ui_html
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
from api.endpoints import router as api_router
|
| 16 |
+
from api.auth import fastapi_users, auth_backend, current_active_user, get_auth_router # أزل أي ذكر لـ google_oauth_router, github_oauth_router
|
| 17 |
from api.database import User, Conversation, get_db, init_db
|
| 18 |
from api.models import UserRead, UserCreate, UserUpdate
|
| 19 |
from motor.motor_asyncio import AsyncIOMotorClient
|
|
|
|
| 141 |
|
| 142 |
# Include routers
|
| 143 |
app.include_router(api_router)
|
| 144 |
+
get_auth_router(app) # يضيف الـ custom OAuth endpoints + JWT + register
|
| 145 |
+
logger.debug("API and auth routers included")
|
|
|
|
|
|
|
| 146 |
|
| 147 |
# Add logout endpoint
|
| 148 |
@app.post("/logout")
|