123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- from functools import lru_cache
- from typing import Literal
- from dotenv import load_dotenv
- from pydantic import model_validator
- from pydantic_settings import BaseSettings, SettingsConfigDict
- from 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 MySQL
- MYSQL_HOST: str
- MYSQL_PORT: int
- MYSQL_USER: str
- MYSQL_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
- API_V1_STR: str = '/api/v1'
- TITLE: str = '3ex AI 接口'
- VERSION: str = '0.0.1'
- DESCRIPTION: str = '3ex AI API'
- DOCS_URL: str | None = f'{API_V1_STR}/docs'
- REDOCS_URL: str | None = f'{API_V1_STR}/redocs'
- OPENAPI_URL: str | None = f'{API_V1_STR}/openapi'
- @model_validator(mode='before')
- @classmethod
- def validate_openapi_url(cls, values):
- if values['ENVIRONMENT'] == 'pro':
- values['OPENAPI_URL'] = None
- return values
- # Demo mode
- # Only GET, OPTIONS requests are allowed
- DEMO_MODE: bool = False
- DEMO_MODE_EXCLUDE: set[tuple[str, str]] = {
- ('POST', f'{API_V1_STR}/auth/login'),
- ('POST', f'{API_V1_STR}/auth/logout'),
- ('GET', f'{API_V1_STR}/auth/captcha'),
- }
- # Static Server
- STATIC_FILES: bool = False
- # Location Parse
- LOCATION_PARSE: Literal['online', 'offline', 'false'] = 'offline'
- # Limiter
- LIMITER_REDIS_PREFIX: str = 'fba:limiter'
- # DateTime
- DATETIME_TIMEZONE: str = 'Asia/Shanghai'
- DATETIME_FORMAT: str = '%Y-%m-%d %H:%M:%S'
- # MySQL
- MYSQL_ECHO: bool = False
- MYSQL_DATABASE: str = 'fba'
- MYSQL_CHARSET: str = 'utf8mb4'
- # Redis
- REDIS_TIMEOUT: int = 5
- # Token
- TOKEN_ALGORITHM: str = 'HS256' # 算法
- TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
- TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 刷新过期时间,单位:秒
- TOKEN_REDIS_PREFIX: str = 'fba:token'
- TOKEN_CALL_REDIS_PREFIX: str = 'fba:call_token'
- TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:token:refresh'
- TOKEN_EXCLUDE: list[str] = [ # JWT / RBAC 白名单
- f'{API_V1_STR}/auth/login',
- ]
- JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
- # Sys User
- USER_REDIS_PREFIX: str = 'fba:user'
- USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
- # Log
- LOG_LEVEL: str = 'INFO'
- LOG_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</> | <lvl>{level: <8}</> | <lvl>{message}</>'
- LOG_STDOUT_FILENAME: str = 'fba_access.log'
- LOG_STDERR_FILENAME: str = 'fba_error.log'
- # Middleware
- MIDDLEWARE_CORS: bool = True
- MIDDLEWARE_ACCESS: bool = True
- # RBAC Permission
- PERMISSION_MODE: Literal['casbin', 'role-menu'] = 'casbin'
- PERMISSION_REDIS_PREFIX: str = 'fba:permission'
- # Casbin Auth
- CASBIN_EXCLUDE: set[tuple[str, str]] = {
- ('POST', f'{API_V1_STR}/auth/logout'),
- ('POST', f'{API_V1_STR}/auth/token/new'),
- }
- # Role Menu Auth
- ROLE_MENU_EXCLUDE: list[str] = [
- 'sys:monitor:redis',
- 'sys:monitor:server',
- ]
- # Opera log
- OPERA_LOG_EXCLUDE: list[str] = [
- '/favicon.ico',
- DOCS_URL,
- REDOCS_URL,
- OPENAPI_URL,
- f'{API_V1_STR}/auth/login/swagger',
- f'{API_V1_STR}/auth/github/callback',
- ]
- OPERA_LOG_ENCRYPT: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ******
- OPERA_LOG_ENCRYPT_INCLUDE: list[str] = [
- 'password',
- 'old_password',
- 'new_password',
- 'confirm_password',
- ]
- # Ip location
- IP_LOCATION_REDIS_PREFIX: str = 'fba:ip:location'
- IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
- @lru_cache
- def get_settings() -> Settings:
- """获取全局配置"""
- load_dotenv()
- return Settings()
- # 创建配置实例
- settings = get_settings()
|