wu981526092 commited on
Commit
1331365
ยท
1 Parent(s): 2553f38

Implement dependency injection authentication system

Browse files

- Create backend/dependencies/auth.py with FastAPI dependencies
- Replace middleware-based auth with dependency injection
- Add get_current_user_optional, get_current_user_required functions
- Add require_auth_in_hf_spaces dependency for route protection
- Update root route to use dependency injection auth
- This avoids session middleware compatibility issues
- Should work properly with SessionMiddleware

backend/app.py CHANGED
@@ -8,13 +8,14 @@ import os
8
  import secrets
9
  from pathlib import Path
10
  import sys
11
- from fastapi import FastAPI, Request, status
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 utils.environment import should_enable_auth, debug_environment
19
 
20
 
@@ -127,9 +128,9 @@ async def shutdown_event():
127
 
128
  # Root redirect to React app (requires authentication)
129
  @app.get("/")
130
- async def root(request: Request):
131
- # This endpoint will be protected by authentication middleware
132
- # If user reaches here, they are authenticated
133
  return RedirectResponse(url="/agentgraph")
134
 
135
 
 
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.auth import require_auth_in_hf_spaces
19
  from utils.environment import should_enable_auth, debug_environment
20
 
21
 
 
128
 
129
  # Root redirect to React app (requires authentication)
130
  @app.get("/")
131
+ async def root(request: Request, auth_check = Depends(require_auth_in_hf_spaces)):
132
+ # This endpoint is protected by dependency injection
133
+ # If user reaches here, they are authenticated (or in local dev)
134
  return RedirectResponse(url="/agentgraph")
135
 
136
 
backend/dependencies/__init__.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Dependencies module for FastAPI dependency injection.
3
+ """
4
+
5
+ from .auth import (
6
+ get_current_user_optional,
7
+ get_current_user_required,
8
+ get_current_user_with_bearer,
9
+ require_auth_in_hf_spaces,
10
+ CurrentUser,
11
+ OptionalUser,
12
+ APIUser,
13
+ RequireHFAuth
14
+ )
15
+
16
+ __all__ = [
17
+ "get_current_user_optional",
18
+ "get_current_user_required",
19
+ "get_current_user_with_bearer",
20
+ "require_auth_in_hf_spaces",
21
+ "CurrentUser",
22
+ "OptionalUser",
23
+ "APIUser",
24
+ "RequireHFAuth"
25
+ ]
backend/dependencies/auth.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Authentication Dependencies for FastAPI
3
+
4
+ This module provides authentication dependencies that can be used
5
+ with FastAPI's dependency injection system instead of middleware.
6
+ """
7
+
8
+ import logging
9
+ from typing import Optional, Dict, Any
10
+ from fastapi import Request, HTTPException, Depends
11
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
12
+ from utils.environment import should_enable_auth, get_oauth_config, is_huggingface_space
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Optional security scheme for Bearer tokens
17
+ security = HTTPBearer(auto_error=False)
18
+
19
+
20
+ def get_current_user_optional(request: Request) -> Optional[Dict[str, Any]]:
21
+ """
22
+ Get current user from session, but don't raise error if not found.
23
+ Used for endpoints where authentication is optional.
24
+ """
25
+ if not should_enable_auth():
26
+ logger.debug("๐Ÿ  Auth disabled - no user required")
27
+ return None
28
+
29
+ # Try to get user from session
30
+ try:
31
+ user = request.session.get("user")
32
+ if user:
33
+ logger.info(f"๐Ÿ”“ Found authenticated user: {user.get('username', 'unknown')}")
34
+ return user
35
+ else:
36
+ logger.debug("๐Ÿ” No user found in session")
37
+ return None
38
+ except Exception as e:
39
+ logger.error(f"Session access failed: {e}")
40
+ return None
41
+
42
+
43
+ def get_current_user_required(request: Request) -> Dict[str, Any]:
44
+ """
45
+ Get current user from session, raise HTTPException if not authenticated.
46
+ Used for endpoints that require authentication.
47
+ """
48
+ if not should_enable_auth():
49
+ logger.debug("๐Ÿ  Auth disabled - returning mock user")
50
+ return {
51
+ "id": "local_dev",
52
+ "username": "local_user",
53
+ "name": "Local Development User",
54
+ "auth_method": "local_dev"
55
+ }
56
+
57
+ user = get_current_user_optional(request)
58
+ if not user:
59
+ logger.warning(f"๐Ÿšซ Authentication required for {request.url.path}")
60
+ raise HTTPException(
61
+ status_code=401,
62
+ detail={
63
+ "error": "Authentication required",
64
+ "message": "Please log in with your Hugging Face account",
65
+ "login_url": "/auth/login"
66
+ }
67
+ )
68
+
69
+ return user
70
+
71
+
72
+ def get_current_user_with_bearer(
73
+ request: Request,
74
+ credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)
75
+ ) -> Optional[Dict[str, Any]]:
76
+ """
77
+ Get current user from session or Bearer token.
78
+ Used for API endpoints that might accept both session and token auth.
79
+ """
80
+ # First try session authentication
81
+ user = get_current_user_optional(request)
82
+ if user:
83
+ return user
84
+
85
+ # If no session user, try Bearer token (for API access)
86
+ if credentials and is_huggingface_space():
87
+ # In a full implementation, validate this token with HF API
88
+ # For now, assume it's valid if present in HF environment
89
+ logger.info("๐Ÿ”‘ User authenticated via Bearer token")
90
+ return {
91
+ "id": "bearer_auth",
92
+ "username": "api_user",
93
+ "name": "API User",
94
+ "auth_method": "bearer_token",
95
+ "token": credentials.credentials
96
+ }
97
+
98
+ return None
99
+
100
+
101
+ # Convenience aliases for common use cases
102
+ CurrentUser = Depends(get_current_user_required)
103
+ OptionalUser = Depends(get_current_user_optional)
104
+ APIUser = Depends(get_current_user_with_bearer)
105
+
106
+
107
+ def require_auth_in_hf_spaces(request: Request) -> None:
108
+ """
109
+ Dependency that enforces authentication only in HF Spaces.
110
+ Raises 401 if in HF Spaces and user is not authenticated.
111
+ """
112
+ if should_enable_auth():
113
+ user = get_current_user_optional(request)
114
+ if not user:
115
+ logger.warning(f"๐Ÿšซ HF Spaces requires authentication for {request.url.path}")
116
+ raise HTTPException(
117
+ status_code=401,
118
+ detail={
119
+ "error": "Authentication required in Hugging Face Spaces",
120
+ "message": "Please log in to access this service",
121
+ "login_url": "/auth/login-page",
122
+ "reason": "This prevents abuse of OpenAI resources"
123
+ }
124
+ )
125
+
126
+
127
+ # Dependency alias for route protection
128
+ RequireHFAuth = Depends(require_auth_in_hf_spaces)