first commit
This commit is contained in:
2
backend/app/api/dependencies/__init__.py
Normal file
2
backend/app/api/dependencies/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
"""Reusable FastAPI dependencies."""
|
||||
|
||||
Binary file not shown.
BIN
backend/app/api/dependencies/__pycache__/auth.cpython-312.pyc
Normal file
BIN
backend/app/api/dependencies/__pycache__/auth.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
42
backend/app/api/dependencies/auth.py
Normal file
42
backend/app/api/dependencies/auth.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from app.application.auth.context import AuthContextService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
|
||||
bearer_scheme = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
|
||||
) -> AuthenticatedUser:
|
||||
"""Resolve current user from a Directus-issued bearer token.
|
||||
|
||||
This keeps auth enforcement centralized and makes later permission mapping
|
||||
easier to add without rewriting every route.
|
||||
"""
|
||||
|
||||
if not credentials or not credentials.credentials:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Authorization header is required.",
|
||||
)
|
||||
|
||||
service = AuthContextService()
|
||||
return await service.get_authenticated_user(credentials.credentials)
|
||||
|
||||
|
||||
async def get_access_token(
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
|
||||
) -> str:
|
||||
"""Return the raw Directus bearer token for repository passthrough reads."""
|
||||
|
||||
if not credentials or not credentials.credentials:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Authorization header is required.",
|
||||
)
|
||||
|
||||
return credentials.credentials
|
||||
36
backend/app/api/dependencies/permissions.py
Normal file
36
backend/app/api/dependencies/permissions.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
|
||||
from app.api.dependencies.auth import get_current_user
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
|
||||
|
||||
def require_permission(permission_name: str) -> Callable[..., AuthenticatedUser]:
|
||||
"""Create a dependency that enforces a translated permission flag.
|
||||
|
||||
The flag names intentionally match `PermissionContextRead` fields so
|
||||
reviewers can trace permission checks end to end without indirection.
|
||||
"""
|
||||
|
||||
async def dependency(
|
||||
current_user: AuthenticatedUser = Depends(get_current_user),
|
||||
) -> AuthenticatedUser:
|
||||
if not hasattr(current_user.permissions, permission_name):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Unknown permission flag '{permission_name}'.",
|
||||
)
|
||||
|
||||
if not getattr(current_user.permissions, permission_name):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"Missing permission '{permission_name}'.",
|
||||
)
|
||||
|
||||
return current_user
|
||||
|
||||
return dependency
|
||||
|
||||
Reference in New Issue
Block a user