#!/usr/bin/env python3 # -*- coding: utf-8 -*- from functools import lru_cache from typing import Any, Literal from pydantic import model_validator from pydantic_settings import BaseSettings, SettingsConfigDict from backend.core.path_conf import BasePath class Settings(BaseSettings): """Global Settings""" model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore') # Env Config ENVIRONMENT: Literal['dev', 'pro'] # Env Database Type DATABASE_TYPE: Literal['mysql', 'postgresql'] # Env Database DATABASE_HOST: str DATABASE_PORT: int DATABASE_USER: str DATABASE_PASSWORD: str # Env Redis REDIS_HOST: str REDIS_PORT: int REDIS_PASSWORD: str REDIS_DATABASE: int # Env Token TOKEN_SECRET_KEY: str # 密钥 secrets.token_urlsafe(32) # Env Opera Log OPERA_LOG_ENCRYPT_SECRET_KEY: str # 密钥 os.urandom(32), 需使用 bytes.hex() 方法转换为 str # FastAPI FASTAPI_API_V1_PATH: str = '/api/v1' FASTAPI_TITLE: str = 'FastAPI' FASTAPI_VERSION: str = '0.0.1' FASTAPI_DESCRIPTION: str = 'FastAPI Best Architecture' FASTAPI_DOCS_URL: str = '/docs' FASTAPI_REDOC_URL: str = '/redoc' FASTAPI_OPENAPI_URL: str | None = '/openapi' FASTAPI_STATIC_FILES: bool = True # Upload UPLOAD_READ_SIZE: int = 1024 # 上传文件时分片读取大小 UPLOAD_IMAGE_EXT_INCLUDE: list[str] = ['jpg', 'jpeg', 'png', 'gif', 'webp'] UPLOAD_IMAGE_SIZE_MAX: int = 1024 * 1024 * 5 UPLOAD_VIDEO_EXT_INCLUDE: list[str] = ['mp4', 'mov', 'avi', 'flv'] UPLOAD_VIDEO_SIZE_MAX: int = 1024 * 1024 * 20 # Database DATABASE_ECHO: bool = False DATABASE_POOL_ECHO: bool = False DATABASE_SCHEMA: str = 'fba' DATABASE_CHARSET: str = 'utf8mb4' # Redis REDIS_TIMEOUT: int = 5 # Socketio WS_NO_AUTH_MARKER: str = 'internal' # Token TOKEN_ALGORITHM: str = 'HS256' # 算法 TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒 TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # refresh token 过期时间,单位:秒 TOKEN_REDIS_PREFIX: str = 'fba:token' TOKEN_EXTRA_INFO_REDIS_PREFIX: str = 'fba:token_extra_info' TOKEN_ONLINE_REDIS_PREFIX: str = 'fba:token_online' TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:refresh_token' TOKEN_REQUEST_PATH_EXCLUDE: list[str] = [ # JWT / RBAC 白名单 f'{FASTAPI_API_V1_PATH}/auth/login', ] # JWT JWT_USER_REDIS_PREFIX: str = 'fba:user' JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # RBAC RBAC_ROLE_MENU_MODE: bool = False RBAC_ROLE_MENU_EXCLUDE: list[str] = [ 'sys:monitor:redis', 'sys:monitor:server', ] # Cookies COOKIE_REFRESH_TOKEN_KEY: str = 'fba_refresh_token' COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS: int = TOKEN_REFRESH_EXPIRE_SECONDS # Log LOG_CID_DEFAULT_VALUE: str = '-' LOG_CID_UUID_LENGTH: int = 32 # must <= 32 LOG_STD_LEVEL: str = 'INFO' LOG_ACCESS_FILE_LEVEL: str = 'INFO' LOG_ERROR_FILE_LEVEL: str = 'ERROR' LOG_STD_FORMAT: str = ( '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | ' ' {correlation_id} | {message}' ) LOG_FILE_FORMAT: str = ( '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | ' ' {correlation_id} | {message}' ) LOG_ACCESS_FILENAME: str = 'fba_access.log' LOG_ERROR_FILENAME: str = 'fba_error.log' # Middleware MIDDLEWARE_CORS: bool = True MIDDLEWARE_ACCESS: bool = True # Trace ID TRACE_ID_REQUEST_HEADER_KEY: str = 'X-Request-ID' # CORS CORS_ALLOWED_ORIGINS: list[str] = [ 'http://127.0.0.1:8000', 'http://localhost:5173', # 前端地址,末尾不要带 '/' ] CORS_EXPOSE_HEADERS: list[str] = [ TRACE_ID_REQUEST_HEADER_KEY, ] # DateTime DATETIME_TIMEZONE: str = 'Asia/Shanghai' DATETIME_FORMAT: str = '%Y-%m-%d %H:%M:%S' # Request limiter REQUEST_LIMITER_REDIS_PREFIX: str = 'fba:limiter' # Demo mode (Only GET, OPTIONS requests are allowed) DEMO_MODE: bool = False DEMO_MODE_EXCLUDE: set[tuple[str, str]] = { ('POST', f'{FASTAPI_API_V1_PATH}/auth/login'), ('POST', f'{FASTAPI_API_V1_PATH}/auth/logout'), ('GET', f'{FASTAPI_API_V1_PATH}/auth/captcha'), } # Ip location IP_LOCATION_PARSE: Literal['online', 'offline', 'false'] = 'offline' IP_LOCATION_REDIS_PREFIX: str = 'fba:ip:location' IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒 # Opera log OPERA_LOG_PATH_EXCLUDE: list[str] = [ '/favicon.ico', FASTAPI_DOCS_URL, FASTAPI_REDOC_URL, FASTAPI_OPENAPI_URL, f'{FASTAPI_API_V1_PATH}/auth/login/swagger', f'{FASTAPI_API_V1_PATH}/oauth2/github/callback', f'{FASTAPI_API_V1_PATH}/oauth2/linux-do/callback', ] OPERA_LOG_ENCRYPT_TYPE: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ****** OPERA_LOG_ENCRYPT_KEY_INCLUDE: list[str] = [ # 将加密接口入参参数对应的值 'password', 'old_password', 'new_password', 'confirm_password', ] # Data permission DATA_PERMISSION_MODELS: dict[ str, str ] = { # 允许进行数据过滤的 SQLA 模型,它必须以模块字符串的方式定义(它应该只用于前台数据,这里只是为了演示) 'Api': 'backend.app.admin.model.Api', } DATA_PERMISSION_COLUMN_EXCLUDE: list[str] = [ # 排除允许进行数据过滤的 SQLA 模型列 'id', 'sort', 'created_time', 'updated_time', ] @model_validator(mode='before') @classmethod def check_env(cls, values: Any) -> Any: if values['ENVIRONMENT'] == 'pro': values['FASTAPI_OPENAPI_URL'] = None values['FASTAPI_STATIC_FILES'] = False return values @lru_cache def get_settings() -> Settings: """获取全局配置""" return Settings() # 创建配置实例 settings = get_settings()