conf.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from functools import lru_cache
  4. from typing import Literal
  5. from dotenv import load_dotenv
  6. from pydantic import model_validator
  7. from pydantic_settings import BaseSettings, SettingsConfigDict
  8. from core.path_conf import BasePath
  9. class Settings(BaseSettings):
  10. """Global Settings"""
  11. model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore')
  12. # Env Config
  13. ENVIRONMENT: Literal['dev', 'pro']
  14. # Env MySQL
  15. MYSQL_HOST: str
  16. MYSQL_PORT: int
  17. MYSQL_USER: str
  18. MYSQL_PASSWORD: str
  19. # Env Redis
  20. REDIS_HOST: str
  21. REDIS_PORT: int
  22. REDIS_PASSWORD: str
  23. REDIS_DATABASE: int
  24. # Env Token
  25. TOKEN_SECRET_KEY: str # 密钥 secrets.token_urlsafe(32)
  26. # Env Opera Log
  27. OPERA_LOG_ENCRYPT_SECRET_KEY: str # 密钥 os.urandom(32), 需使用 bytes.hex() 方法转换为 str
  28. # FastAPI
  29. API_V1_STR: str = '/api/v1'
  30. TITLE: str = '3ex AI 接口'
  31. VERSION: str = '0.0.1'
  32. DESCRIPTION: str = '3ex AI API'
  33. DOCS_URL: str | None = f'{API_V1_STR}/docs'
  34. REDOCS_URL: str | None = f'{API_V1_STR}/redocs'
  35. OPENAPI_URL: str | None = f'{API_V1_STR}/openapi'
  36. @model_validator(mode='before')
  37. @classmethod
  38. def validate_openapi_url(cls, values):
  39. if values['ENVIRONMENT'] == 'pro':
  40. values['OPENAPI_URL'] = None
  41. return values
  42. # Demo mode
  43. # Only GET, OPTIONS requests are allowed
  44. DEMO_MODE: bool = False
  45. DEMO_MODE_EXCLUDE: set[tuple[str, str]] = {
  46. ('POST', f'{API_V1_STR}/auth/login'),
  47. ('POST', f'{API_V1_STR}/auth/logout'),
  48. ('GET', f'{API_V1_STR}/auth/captcha'),
  49. }
  50. # Static Server
  51. STATIC_FILES: bool = False
  52. # Location Parse
  53. LOCATION_PARSE: Literal['online', 'offline', 'false'] = 'offline'
  54. # Limiter
  55. LIMITER_REDIS_PREFIX: str = 'fba:limiter'
  56. # DateTime
  57. DATETIME_TIMEZONE: str = 'Asia/Shanghai'
  58. DATETIME_FORMAT: str = '%Y-%m-%d %H:%M:%S'
  59. # MySQL
  60. MYSQL_ECHO: bool = False
  61. MYSQL_DATABASE: str = 'fba'
  62. MYSQL_CHARSET: str = 'utf8mb4'
  63. # Redis
  64. REDIS_TIMEOUT: int = 5
  65. # Token
  66. TOKEN_ALGORITHM: str = 'HS256' # 算法
  67. TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
  68. TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 刷新过期时间,单位:秒
  69. TOKEN_REDIS_PREFIX: str = 'fba:token'
  70. TOKEN_CALL_REDIS_PREFIX: str = 'fba:call_token'
  71. TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:token:refresh'
  72. TOKEN_EXCLUDE: list[str] = [ # JWT / RBAC 白名单
  73. f'{API_V1_STR}/auth/login',
  74. ]
  75. JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
  76. # Sys User
  77. USER_REDIS_PREFIX: str = 'fba:user'
  78. USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
  79. # Log
  80. LOG_LEVEL: str = 'INFO'
  81. LOG_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</> | <lvl>{level: <8}</> | <lvl>{message}</>'
  82. LOG_STDOUT_FILENAME: str = 'fba_access.log'
  83. LOG_STDERR_FILENAME: str = 'fba_error.log'
  84. # Middleware
  85. MIDDLEWARE_CORS: bool = True
  86. MIDDLEWARE_ACCESS: bool = True
  87. # RBAC Permission
  88. PERMISSION_MODE: Literal['casbin', 'role-menu'] = 'casbin'
  89. PERMISSION_REDIS_PREFIX: str = 'fba:permission'
  90. # Casbin Auth
  91. CASBIN_EXCLUDE: set[tuple[str, str]] = {
  92. ('POST', f'{API_V1_STR}/auth/logout'),
  93. ('POST', f'{API_V1_STR}/auth/token/new'),
  94. }
  95. # Role Menu Auth
  96. ROLE_MENU_EXCLUDE: list[str] = [
  97. 'sys:monitor:redis',
  98. 'sys:monitor:server',
  99. ]
  100. # Opera log
  101. OPERA_LOG_EXCLUDE: list[str] = [
  102. '/favicon.ico',
  103. DOCS_URL,
  104. REDOCS_URL,
  105. OPENAPI_URL,
  106. f'{API_V1_STR}/auth/login/swagger',
  107. f'{API_V1_STR}/auth/github/callback',
  108. ]
  109. OPERA_LOG_ENCRYPT: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ******
  110. OPERA_LOG_ENCRYPT_INCLUDE: list[str] = [
  111. 'password',
  112. 'old_password',
  113. 'new_password',
  114. 'confirm_password',
  115. ]
  116. # Ip location
  117. IP_LOCATION_REDIS_PREFIX: str = 'fba:ip:location'
  118. IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
  119. @lru_cache
  120. def get_settings() -> Settings:
  121. """获取全局配置"""
  122. load_dotenv()
  123. return Settings()
  124. # 创建配置实例
  125. settings = get_settings()