Spaces:
Sleeping
Sleeping
Commit
·
188f8a3
1
Parent(s):
97068b2
Add smart authentication redirect system
Browse files- Add custom HTTPException handler in app.py
- Distinguish between API and web requests
- Web requests get redirected to /auth/login-page (302)
- API requests get JSON error response (401)
- Check Accept and Content-Type headers for request type detection
- Improve user experience by avoiding JSON errors in browser
- backend/app.py +27 -2
- backend/dependencies.py +30 -8
backend/app.py
CHANGED
|
@@ -8,11 +8,12 @@ import os
|
|
| 8 |
import secrets
|
| 9 |
from pathlib import Path
|
| 10 |
import sys
|
| 11 |
-
from fastapi import FastAPI, Request, status, Depends
|
| 12 |
from fastapi.staticfiles import StaticFiles
|
| 13 |
from fastapi.middleware.cors import CORSMiddleware
|
| 14 |
from starlette.middleware.sessions import SessionMiddleware
|
| 15 |
-
from fastapi.responses import RedirectResponse, HTMLResponse
|
|
|
|
| 16 |
from backend.middleware.auth import ConditionalAuthMiddleware
|
| 17 |
from backend.middleware.usage_tracker import UsageTrackingMiddleware
|
| 18 |
from backend.dependencies import require_auth_in_hf_spaces
|
|
@@ -71,6 +72,30 @@ app.add_middleware(
|
|
| 71 |
# Add usage tracking middleware (last, to track authenticated requests)
|
| 72 |
app.add_middleware(UsageTrackingMiddleware)
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
# Mount datasets directory for accessing json files
|
| 75 |
app.mount("/data", StaticFiles(directory="datasets"), name="data")
|
| 76 |
|
|
|
|
| 8 |
import secrets
|
| 9 |
from pathlib import Path
|
| 10 |
import sys
|
| 11 |
+
from fastapi import FastAPI, Request, status, Depends, HTTPException
|
| 12 |
from fastapi.staticfiles import StaticFiles
|
| 13 |
from fastapi.middleware.cors import CORSMiddleware
|
| 14 |
from starlette.middleware.sessions import SessionMiddleware
|
| 15 |
+
from fastapi.responses import RedirectResponse, HTMLResponse, JSONResponse
|
| 16 |
+
from fastapi.exception_handlers import http_exception_handler
|
| 17 |
from backend.middleware.auth import ConditionalAuthMiddleware
|
| 18 |
from backend.middleware.usage_tracker import UsageTrackingMiddleware
|
| 19 |
from backend.dependencies import require_auth_in_hf_spaces
|
|
|
|
| 72 |
# Add usage tracking middleware (last, to track authenticated requests)
|
| 73 |
app.add_middleware(UsageTrackingMiddleware)
|
| 74 |
|
| 75 |
+
# Custom exception handler for authentication redirects
|
| 76 |
+
@app.exception_handler(HTTPException)
|
| 77 |
+
async def custom_http_exception_handler(request: Request, exc: HTTPException):
|
| 78 |
+
"""
|
| 79 |
+
Custom exception handler that redirects web requests to login page
|
| 80 |
+
when they receive 401 errors with redirect_to field.
|
| 81 |
+
"""
|
| 82 |
+
# Check if this is a 401 with redirect_to field
|
| 83 |
+
if exc.status_code == 401 and isinstance(exc.detail, dict) and "redirect_to" in exc.detail:
|
| 84 |
+
# Check if this is not an API request
|
| 85 |
+
is_api_request = (
|
| 86 |
+
request.url.path.startswith("/api/") or
|
| 87 |
+
request.headers.get("accept", "").startswith("application/json") or
|
| 88 |
+
request.headers.get("content-type", "").startswith("application/json")
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
if not is_api_request:
|
| 92 |
+
# Redirect web requests to login page
|
| 93 |
+
logger.info(f"🔄 Redirecting unauthenticated user from {request.url.path} to login page")
|
| 94 |
+
return RedirectResponse(url=exc.detail["redirect_to"], status_code=302)
|
| 95 |
+
|
| 96 |
+
# For all other cases, use default exception handler
|
| 97 |
+
return await http_exception_handler(request, exc)
|
| 98 |
+
|
| 99 |
# Mount datasets directory for accessing json files
|
| 100 |
app.mount("/data", StaticFiles(directory="datasets"), name="data")
|
| 101 |
|
backend/dependencies.py
CHANGED
|
@@ -167,15 +167,37 @@ def require_auth_in_hf_spaces(request: Request) -> None:
|
|
| 167 |
user = get_current_user_optional(request)
|
| 168 |
if not user:
|
| 169 |
logger.warning(f"🚫 HF Spaces requires authentication for {request.url.path}")
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
"reason": "This prevents abuse of OpenAI resources"
|
| 177 |
-
}
|
| 178 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
|
| 181 |
# Convenience aliases for common use cases
|
|
|
|
| 167 |
user = get_current_user_optional(request)
|
| 168 |
if not user:
|
| 169 |
logger.warning(f"🚫 HF Spaces requires authentication for {request.url.path}")
|
| 170 |
+
|
| 171 |
+
# Check if this is an API request or web request
|
| 172 |
+
is_api_request = (
|
| 173 |
+
request.url.path.startswith("/api/") or
|
| 174 |
+
request.headers.get("accept", "").startswith("application/json") or
|
| 175 |
+
request.headers.get("content-type", "").startswith("application/json")
|
|
|
|
|
|
|
| 176 |
)
|
| 177 |
+
|
| 178 |
+
if is_api_request:
|
| 179 |
+
# For API requests, return JSON error
|
| 180 |
+
raise HTTPException(
|
| 181 |
+
status_code=401,
|
| 182 |
+
detail={
|
| 183 |
+
"error": "Authentication required in Hugging Face Spaces",
|
| 184 |
+
"message": "Please log in to access this service",
|
| 185 |
+
"login_url": "/auth/login-page",
|
| 186 |
+
"reason": "This prevents abuse of OpenAI resources"
|
| 187 |
+
}
|
| 188 |
+
)
|
| 189 |
+
else:
|
| 190 |
+
# For web requests, include redirect info in the error
|
| 191 |
+
# This will be handled by our custom exception handler
|
| 192 |
+
raise HTTPException(
|
| 193 |
+
status_code=401,
|
| 194 |
+
detail={
|
| 195 |
+
"error": "Authentication required in Hugging Face Spaces",
|
| 196 |
+
"message": "Please log in to access this service",
|
| 197 |
+
"redirect_to": "/auth/login-page",
|
| 198 |
+
"reason": "This prevents abuse of OpenAI resources"
|
| 199 |
+
}
|
| 200 |
+
)
|
| 201 |
|
| 202 |
|
| 203 |
# Convenience aliases for common use cases
|