feat: Implement multi-tenancy support in middleware and security layers

- Enhanced TenantMiddleware to validate tenant information from JWT tokens.
- Added LicenseValidationMiddleware to check tenant licenses before processing requests.
- Updated security utilities to extract tenant information from tokens and validate company access.
- Introduced CompanyStore to manage active company state and handle company switching in the frontend.
- Modified API routes to include company_id in requests for better resource management.
- Improved logging and error handling throughout the middleware and API layers.
- Updated frontend components to reflect changes in company management and selection.
- Added new API route for fetching user's companies with proper authentication handling.
This commit is contained in:
2025-11-11 14:00:56 -06:00
parent e1eb6bbd01
commit 52b8fcd434
242 changed files with 7067 additions and 3274 deletions

View File

@@ -1,26 +1,27 @@
"""
Configuración centralizada de la aplicación usando Pydantic Settings
"""
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import List
class Settings(BaseSettings):
"""Configuración de la aplicación"""
# Application
APP_NAME: str = "Anexo76"
APP_VERSION: str = "1.0.0"
DEBUG: bool = True
ENVIRONMENT: str = "development"
# Database - Core (Shared)
CORE_DB_HOST: str = "postgres-a76"
CORE_DB_PORT: int = 5432
CORE_DB_NAME: str = "anexo76_core"
CORE_DB_USER: str = "postgres"
CORE_DB_PASSWORD: str = "postgres"
# Keycloak
KEYCLOAK_SERVER_URL: str = "http://localhost:8080"
KEYCLOAK_REALM: str = "master"
@@ -28,34 +29,32 @@ class Settings(BaseSettings):
KEYCLOAK_CLIENT_SECRET: str = ""
KEYCLOAK_ADMIN_USERNAME: str = "admin"
KEYCLOAK_ADMIN_PASSWORD: str = "admin"
# Security
SECRET_KEY: str = "change-this-secret-key-in-production"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# CORS
CORS_ORIGINS: str = "http://localhost:5173,http://localhost:3000"
# License
LICENSE_CHECK_ENABLED: bool = True
model_config = SettingsConfigDict(
env_file=".env",
case_sensitive=True,
extra="ignore"
env_file=".env", case_sensitive=True, extra="ignore"
)
@property
def core_database_url(self) -> str:
"""URL de conexión a la base de datos core"""
return f"postgresql://{self.CORE_DB_USER}:{self.CORE_DB_PASSWORD}@{self.CORE_DB_HOST}:{self.CORE_DB_PORT}/{self.CORE_DB_NAME}"
@property
def async_core_database_url(self) -> str:
"""URL de conexión asíncrona a la base de datos core"""
return f"postgresql+asyncpg://{self.CORE_DB_USER}:{self.CORE_DB_PASSWORD}@{self.CORE_DB_HOST}:{self.CORE_DB_PORT}/{self.CORE_DB_NAME}"
@property
def cors_origins_list(self) -> List[str]:
"""Lista de orígenes CORS permitidos"""