feat: update auth logic

This commit is contained in:
2026-06-09 19:37:32 +03:00
parent e1f074b94d
commit 6c3628edfa
12 changed files with 40 additions and 189 deletions

View File

@@ -1,47 +0,0 @@
from fastapi import Depends, Request
from fastapi.security.utils import get_authorization_scheme_param
from src.application.contracts import IJwtService
from src.application.domain.dto import AdminAuthContext
from src.application.domain.exceptions import ForbiddenException, UnauthorizedException
from src.presentation.dependencies.security import get_jwt_service
def _extract_bearer_token(request: Request) -> str | None:
auth = request.headers.get('Authorization')
if not auth:
return None
scheme, param = get_authorization_scheme_param(auth)
if scheme.lower() == 'bearer' and param:
return param
return None
async def require_admin_access(
request: Request,
jwt_service: IJwtService = Depends(get_jwt_service),
) -> AdminAuthContext:
token = _extract_bearer_token(request)
if not token:
raise UnauthorizedException(message='Authorization Bearer token required')
payload = await jwt_service.decode_access_token(token)
if payload.type != 'access':
raise UnauthorizedException(message='Invalid token type')
role = payload.role
if not role:
raise UnauthorizedException(message='Token missing role')
return AdminAuthContext(admin_user_id=payload.sub, role=role)
def require_admin_role(*allowed_roles: str):
allowed = set(allowed_roles)
async def dependency(auth: AdminAuthContext = Depends(require_admin_access)) -> AdminAuthContext:
if auth.role not in allowed:
raise ForbiddenException(message='Insufficient permissions')
return auth
return dependency

View File

@@ -7,7 +7,6 @@ from src.application.commands import (
GetOrganizationSecretKeysCommand,
GetPurchaseRequestCommand,
ListOrganizationWalletsCommand,
ListOrganizationsCommand,
ListPurchaseRequestsCommand,
)
from src.application.contracts import ILogger
@@ -36,13 +35,6 @@ def get_get_purchase_request_command(
return GetPurchaseRequestCommand(unit_of_work=unit_of_work, logger=logger)
def get_list_organizations_command(
logger: ILogger = Depends(get_logger),
unit_of_work: IUnitOfWork = Depends(get_unit_of_work),
) -> ListOrganizationsCommand:
return ListOrganizationsCommand(unit_of_work=unit_of_work, logger=logger)
def get_get_organization_command(
logger: ILogger = Depends(get_logger),
unit_of_work: IUnitOfWork = Depends(get_unit_of_work),

View File

@@ -1,24 +1,21 @@
from fastapi import APIRouter, Depends, Query
from fastapi import APIRouter, Depends
from src.application.commands import (
GetOrganizationCommand,
GetOrganizationMnemonicCommand,
GetOrganizationSecretKeysCommand,
ListOrganizationWalletsCommand,
ListOrganizationsCommand,
)
from src.application.domain.dto import AdminAuthContext
from src.presentation.decorators.admin_auth import require_admin_access, require_admin_role
from src.application.domain.dto import AuthContext
from src.presentation.decorators.auth import require_access_token
from src.presentation.dependencies.commands import (
get_get_organization_command,
get_get_organization_mnemonic_command,
get_get_organization_secret_keys_command,
get_list_organization_wallets_command,
get_list_organizations_command,
)
from src.presentation.schemas.organization import (
MnemonicResponse,
OrganizationListResponse,
OrganizationResponse,
SecretKeyResponse,
WalletResponse,
@@ -33,57 +30,39 @@ from src.presentation.serializers.organization import (
organizations_router = APIRouter(prefix='/organizations', tags=['organizations'])
@organizations_router.get('', response_model=OrganizationListResponse)
async def list_organizations(
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
auth: AdminAuthContext = Depends(require_admin_access),
command: ListOrganizationsCommand = Depends(get_list_organizations_command),
):
items, total = await command(limit=limit, offset=offset)
return OrganizationListResponse(
items=[organization_to_response(x) for x in items],
total=total,
)
@organizations_router.get('/{organization_id}', response_model=OrganizationResponse)
@organizations_router.get('', response_model=OrganizationResponse)
async def get_organization(
organization_id: str,
auth: AdminAuthContext = Depends(require_admin_access),
auth: AuthContext = Depends(require_access_token),
command: GetOrganizationCommand = Depends(get_get_organization_command),
):
org = await command(organization_id)
org = await command(auth.user_id)
return organization_to_response(org)
@organizations_router.get('/{organization_id}/wallets', response_model=list[WalletResponse])
@organizations_router.get('/wallets', response_model=list[WalletResponse])
async def list_organization_wallets(
organization_id: str,
auth: AdminAuthContext = Depends(require_admin_access),
auth: AuthContext = Depends(require_access_token),
command: ListOrganizationWalletsCommand = Depends(get_list_organization_wallets_command),
):
wallets = await command(organization_id)
wallets = await command(auth.user_id)
return [wallet_to_response(w) for w in wallets]
@organizations_router.get('/{organization_id}/wallets/mnemonic', response_model=MnemonicResponse)
@organizations_router.get('/wallets/mnemonic', response_model=MnemonicResponse)
async def get_organization_mnemonic(
organization_id: str,
auth: AdminAuthContext = Depends(require_admin_role('compliance', 'superadmin')),
auth: AuthContext = Depends(require_access_token),
command: GetOrganizationMnemonicCommand = Depends(get_get_organization_mnemonic_command),
):
mnemonic = await command(organization_id)
mnemonic = await command(auth.user_id)
return mnemonic_to_response(mnemonic)
@organizations_router.get('/{organization_id}/wallets/secret-keys', response_model=list[SecretKeyResponse])
@organizations_router.get('/wallets/secret-keys', response_model=list[SecretKeyResponse])
async def get_organization_secret_keys(
organization_id: str,
auth: AdminAuthContext = Depends(require_admin_role('compliance', 'superadmin')),
auth: AuthContext = Depends(require_access_token),
command: GetOrganizationSecretKeysCommand = Depends(get_get_organization_secret_keys_command),
):
keys = await command(organization_id)
keys = await command(auth.user_id)
return [
secret_key_to_response(
chain=k.chain,

View File

@@ -27,11 +27,6 @@ class OrganizationResponse(BaseModel):
updated_at: str | None
class OrganizationListResponse(BaseModel):
items: list[OrganizationResponse]
total: int
class WalletResponse(BaseModel):
id: str
chain: str