chore: 基线提交(重构前代码快照)

- git 初始化 + .gitignore 补全(根 .env / logs / instance / __pycache__ 等)
- 修复 utils/.gitignore 误将整个 utils/ 源码层忽略的问题,补入全部工具源码(含 ip2region.xdb)
- 含后端全部代码:application / extensions / utils / config / migrations
- 含前端 ui/(后续整体迁走)
- 不含根 .env(含密钥,本地保留)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 12:12:06 +08:00
co-authored by Claude
commit 15f2a5e097
591 changed files with 95894 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
"""
配置模块入口
=============================================================
负责:
1. 加载 .env 环境变量(最先执行,保证子模块能读取配置)
2. 重新导出所有子模块的配置项,供业务代码统一使用
使用方式:
from config import FLASK_DEMO, DATABASE_URL, REDIS_URL, JWT_SALT
"""
import os
from dotenv import load_dotenv
def _load_env_file():
"""加载 .env 配置文件"""
root_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
env_path = os.path.join(root_path, '.env')
if os.path.exists(env_path):
load_dotenv(env_path)
return True
return False
# 在任何 config 子模块被 import 之前加载 .env
_load_env_file()
# ============================================================
# 重新导出所有子模块配置(统一入口)
# ============================================================
# 应用基础配置
from config.app import (
FLASK_NAME, FLASK_VERSION, FLASK_SECRET_KEY, FLASK_HOST, FLASK_PORT,
FLASK_SITE_DOMAIN, FLASK_APP, FLASK_ENV, FLASK_DEBUG, FLASK_USE_RELOADER,
FLASK_DEMO, FLASK_SYSTEM, FLASK_ROOT_PATH, FLASK_TEMPLATE_FOLDER,
FLASK_STATIC_FOLDER, FLASK_UPLOAD_DIR, FLASK_TEMP_PATH, FLASK_FILE_URL,
UPLOAD_ALLOWED_EXTS, UPLOAD_MAX_SIZE_MB, CORS_ALLOWED_ORIGINS,
)
# 数据库配置
from config.database import (
DatabaseConfig, DB_PREFIX, DB_DRIVER, DB_HOST, DB_PORT, DB_DATABASE,
DB_USERNAME, DB_PASSWORD, DB_DEBUG, DB_SSL, DATABASE_URL,
)
# Redis 缓存配置
from config.redis import (
REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_INDEX,
REDIS_AUTH, REDIS_DECODE_RESPONSES, REDIS_URL,
)
# JWT + 权限 + 白名单配置
from config.auth import (
JWT_SALT, JWT_EXPIRE_MINUTES, LOGIN_FAIL_MAX, LOGIN_LOCK_SECONDS,
PERMISSION_ENABLED, INTERNAL_API_KEY,
INTERNAL_ALLOWED_IPS, LOGIN_WHITELIST_EXACT, LOGIN_WHITELIST_PREFIX,
LOGIN_WHITELIST_WILDCARD, LOGIN_WHITELIST_DEBUG, LOGIN_WHITELIST_LOG_ACCESS,
CAPTCHA_BYPASS_CODE,
)
# 邮件配置
from config.mail import (
MAIL_MAILER, MAIL_SERVER, MAIL_PORT, MAIL_USE_SSL,
MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION,
MAIL_FROM_NAME, MAIL_FROM_ADDRESS,
)
# 短信配置
from config.sms import (
SMS_PROVIDER, SMS_ALIYUN_ACCESS_KEY_ID, SMS_ALIYUN_ACCESS_KEY_SECRET,
SMS_ALIYUN_SIGN_NAME, SMS_ALIYUN_ENDPOINT,
SMS_ALIYUN_CONNECT_TIMEOUT, SMS_ALIYUN_READ_TIMEOUT,
)
# 验证码配置
from config.captcha import (
CAPTCHA_LENGTH,
CAPTCHA_EXPIRE,
CAPTCHA_RATE_LIMIT,
CAPTCHA_RATE_WINDOW,
CAPTCHA_CHARS,
CAPTCHA_FONT_PATH,
CAPTCHA_IMAGE_WIDTH,
CAPTCHA_IMAGE_HEIGHT,
CAPTCHA_FONT_SIZE,
CAPTCHA_NOISE_LINES,
CAPTCHA_NOISE_DOTS,
)
__all__ = [
# 应用基础配置
'FLASK_NAME', 'FLASK_VERSION', 'FLASK_SECRET_KEY', 'FLASK_HOST', 'FLASK_PORT',
'FLASK_SITE_DOMAIN', 'FLASK_APP', 'FLASK_ENV', 'FLASK_DEBUG', 'FLASK_USE_RELOADER',
'FLASK_DEMO', 'FLASK_SYSTEM', 'FLASK_ROOT_PATH', 'FLASK_TEMPLATE_FOLDER',
'FLASK_STATIC_FOLDER', 'FLASK_UPLOAD_DIR', 'FLASK_TEMP_PATH', 'FLASK_FILE_URL',
'UPLOAD_ALLOWED_EXTS', 'UPLOAD_MAX_SIZE_MB', 'CORS_ALLOWED_ORIGINS',
# 数据库配置
'DatabaseConfig', 'DB_PREFIX', 'DB_DRIVER', 'DB_HOST', 'DB_PORT', 'DB_DATABASE',
'DB_USERNAME', 'DB_PASSWORD', 'DB_DEBUG', 'DB_SSL', 'DATABASE_URL',
# Redis 配置
'REDIS_HOST', 'REDIS_PORT', 'REDIS_PASSWORD', 'REDIS_INDEX',
'REDIS_AUTH', 'REDIS_DECODE_RESPONSES', 'REDIS_URL',
# JWT + 权限 + 白名单配置
'JWT_SALT', 'JWT_EXPIRE_MINUTES', 'LOGIN_FAIL_MAX', 'LOGIN_LOCK_SECONDS',
'PERMISSION_ENABLED', 'INTERNAL_API_KEY',
'INTERNAL_ALLOWED_IPS', 'LOGIN_WHITELIST_EXACT', 'LOGIN_WHITELIST_PREFIX',
'LOGIN_WHITELIST_WILDCARD', 'LOGIN_WHITELIST_DEBUG', 'LOGIN_WHITELIST_LOG_ACCESS',
'CAPTCHA_BYPASS_CODE',
# 邮件配置
'MAIL_MAILER', 'MAIL_SERVER', 'MAIL_PORT', 'MAIL_USE_SSL',
'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION',
'MAIL_FROM_NAME', 'MAIL_FROM_ADDRESS',
# 短信配置
'SMS_PROVIDER', 'SMS_ALIYUN_ACCESS_KEY_ID', 'SMS_ALIYUN_ACCESS_KEY_SECRET',
'SMS_ALIYUN_SIGN_NAME', 'SMS_ALIYUN_ENDPOINT',
'SMS_ALIYUN_CONNECT_TIMEOUT', 'SMS_ALIYUN_READ_TIMEOUT',
# 验证码配置
'CAPTCHA_LENGTH', 'CAPTCHA_EXPIRE', 'CAPTCHA_RATE_LIMIT', 'CAPTCHA_RATE_WINDOW',
'CAPTCHA_CHARS', 'CAPTCHA_FONT_PATH', 'CAPTCHA_IMAGE_WIDTH',
'CAPTCHA_IMAGE_HEIGHT', 'CAPTCHA_FONT_SIZE',
'CAPTCHA_NOISE_LINES', 'CAPTCHA_NOISE_DOTS',
]
+126
View File
@@ -0,0 +1,126 @@
"""
Flask 基础配置模块
=============================================================
包含 Flask 应用运行所需的基础配置项,如应用名称、版本、
运行地址、端口、调试模式、文件存储路径等。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
import platform
# ============================================================
# 应用基础配置
# ============================================================
# 应用名称 - 用于界面标题、日志标识、API文档标题等
# 从环境变量读取,默认值为 DEMO
FLASK_NAME = os.getenv('FLASK_NAME', 'DEMO')
# 应用版本号 - 用于版本追踪、API版本控制和更新检测
# 格式遵循语义化版本规范 v主版本.次版本.补丁版本
FLASK_VERSION = os.getenv('FLASK_VERSION', 'v2.8.0')
# 应用秘钥 - 用于Session加密、CSRF保护、签名生成
# 生产环境务必使用强随机字符串,长度至少32字符
# 生成命令:python -c "import secrets; print(secrets.token_hex(32))"
FLASK_SECRET_KEY = os.getenv('FLASK_SECRET_KEY', '')
# 应用运行地址 - 127.0.0.1 仅本地访问,0.0.0.0 允许外部访问
# 生产环境建议使用 0.0.0.0 配合 Nginx 反向代理
FLASK_HOST = os.getenv('FLASK_HOST', '127.0.0.1')
# 应用运行端口 - 确保端口未被其他服务占用
# 常用端口:8021(开发)、80(HTTP)、443(HTTPS)
FLASK_PORT = int(os.getenv('FLASK_PORT', 8021))
# 站点域名 - 用于定时任务、邮件模板、微信回调等场景构建完整URL
# 自动根据 HOST 和 PORT 生成,生产环境建议手动配置为真实域名
FLASK_SITE_DOMAIN = f'http://{FLASK_HOST}:{FLASK_PORT}'
# 应用启动文件 - Flask 入口文件名
# 通常为 app.py 或 base.py
FLASK_APP = os.getenv('FLASK_APP', 'base.py')
# 应用环境变量 - development(开发环境)/ production(生产环境)
# 不同环境会加载不同的配置,如日志级别、调试开关等
FLASK_ENV = os.getenv('FLASK_ENV', 'development')
# 是否调试模式 - True 开启调试 / False 关闭调试
# 开发环境开启可获得详细错误信息和自动重载
# 生产环境必须设为 False,否则会暴露敏感信息
FLASK_DEBUG = os.getenv('FLASK_DEBUG', 'True') == 'True'
# 是否禁用自动重启 - True 禁用 / False 启用
# 仅在 FLASK_DEBUG=True 时生效,生产环境无关
# 设为 True 可避免频繁重启导致的问题
FLASK_USE_RELOADER = os.getenv('FLASK_USE_RELOADER', 'True') == 'True'
# 是否演示模式 - True 演示模式(限制操作权限)/ False 正常模式
# 演示模式下会禁用删除、修改等危险操作
# 默认关闭,防止 .env 缺失时误入演示模式
FLASK_DEMO = os.getenv('FLASK_DEMO', 'False') == 'True'
# 系统环境 - windows / linux / darwin(macOS)
# 用于适配不同操作系统的文件路径、命令等差异
FLASK_SYSTEM = platform.system().lower()
# ============================================================
# 路径配置
# ============================================================
# 应用根目录 - 项目的最顶层目录
# 用于定位模板、静态资源、上传文件等
FLASK_ROOT_PATH = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# 应用模板路径 - Jinja2 模板文件存放目录
# 用于渲染 HTML 页面
FLASK_TEMPLATE_FOLDER = os.path.join(FLASK_ROOT_PATH, 'templates')
# 应用静态资源路径 - CSS、JS、图片等前端资源存放目录
# 通过 /static/ 路由访问
FLASK_STATIC_FOLDER = os.path.join(FLASK_ROOT_PATH, 'static')
# 应用文件存储路径 - 用户上传文件的存储目录
# 建议与代码分离,方便备份和迁移
FLASK_UPLOAD_DIR = os.getenv('FLASK_UPLOAD_DIR', os.path.join(FLASK_ROOT_PATH, 'uploads'))
# 临时文件路径 - 用于存放临时文件(如导入导出时的缓存)
# 建议定期清理,避免占用过多磁盘空间
FLASK_TEMP_PATH = FLASK_UPLOAD_DIR + '/temp'
# 应用图片域名 - 用于生成图片完整URL
# 生产环境应配置为CDN域名或文件服务域名
# 示例:https://cdn.example.com 或 http://images.example.com
FLASK_FILE_URL = os.getenv('FLASK_FILE_URL', '')
# ============================================================
# 文件上传安全配置
# ============================================================
# 允许上传的文件扩展名(逗号分隔,带点号)
# 生产环境务必严格配置,防止上传危险文件
# 安全扩展名:图片、文档、压缩包、音视频
# 危险扩展名:.py、.exe、.sh、.bat、.php、.jsp、.asp 等
UPLOAD_ALLOWED_EXTS = os.getenv(
'UPLOAD_ALLOWED_EXTS',
'.jpg,.jpeg,.png,.gif,.bmp,.webp,.svg,.ico,.txt,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4,.zip,.rar,.7z'
)
# 上传文件大小上限(MB)- 超过此大小将被拒绝上传
# 防止用户上传超大文件导致磁盘空间耗尽或带宽拥堵
# 建议根据业务需求调整:普通文件 10MB,高清图片 20MB,视频 100MB+
UPLOAD_MAX_SIZE_MB = int(os.getenv('UPLOAD_MAX_SIZE_MB', 10))
# ============================================================
# CORS 跨域配置
# ============================================================
# 允许的源(逗号分隔,如 http://localhost:8001,https://admin.example.com)
# 配置后支持携带凭证(Cookie、Authorization头等)
# 未配置则允许所有源(*)但不允许携带凭证
# 生产环境应明确列出允许的前端域名,避免使用通配符
# 示例:http://localhost:8080,https://admin.yourdomain.com
CORS_ALLOWED_ORIGINS = os.getenv('CORS_ALLOWED_ORIGINS', '')
+82
View File
@@ -0,0 +1,82 @@
"""
认证与权限配置模块
=============================================================
包含 JWT 令牌、权限验证、登录白名单相关的所有配置项。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
import logging
logger = logging.getLogger(__name__)
# ============================================================
# JWT令牌配置
# ============================================================
# JWT密钥(用于令牌签名和验证,必须保密)
# 从环境变量读取,未配置则拒绝启动,防止使用已知弱密钥
JWT_SALT = os.getenv('JWT_SALT', '')
# JWT令牌过期时间(分钟)
JWT_EXPIRE_MINUTES = int(os.getenv('JWT_EXPIRE_MINUTES', 20))
# 登录失败次数上限(同一IP+用户名连续失败超过此次数后锁定)
LOGIN_FAIL_MAX = int(os.getenv('LOGIN_FAIL_MAX', 5))
# 登录锁定时间(秒)(锁定期间禁止该IP+用户名登录)
LOGIN_LOCK_SECONDS = int(os.getenv('LOGIN_LOCK_SECONDS', 300))
# ============================================================
# 权限验证配置
# ============================================================
# 是否启用权限验证:True-启用(需要登录验证),False-禁用(所有请求放行)
PERMISSION_ENABLED = os.getenv('PERMISSION_ENABLED', 'True') == 'True'
# 系统内部调用的API密钥(用于定时任务等无用户场景)
# 调用方需在请求头中携带 X-Internal-API-Key 或 X-Scheduler-Key
INTERNAL_API_KEY = os.getenv('INTERNAL_API_KEY', '')
# 启动时校验:未配置则拒绝启动,防止定时任务权限验证失效
if not INTERNAL_API_KEY:
raise RuntimeError(
"INTERNAL_API_KEY 未配置!请在 .env 中设置内部调用密钥。\n"
"生成方式:python -c \"import secrets; print(secrets.token_urlsafe(32))\""
)
# 内部调用白名单IP(逗号分隔,支持通配符如 127.0.0.*)
# 在此列表中的IP发起的请求将跳过权限验证
INTERNAL_ALLOWED_IPS = os.getenv('INTERNAL_ALLOWED_IPS', '127.0.0.1')
# ============================================================
# 登录白名单配置(支持通配符)
# ============================================================
# 精确匹配白名单(逗号分隔,完全匹配路径才放行)
# 支持路径:/login、/captcha、/favicon.ico
LOGIN_WHITELIST_EXACT = os.getenv('LOGIN_WHITELIST_EXACT', '')
# 前缀匹配白名单(逗号分隔,路径以此开头即放行)
# 支持路径:/job/sendSms、/public、/static、/api/webhook
LOGIN_WHITELIST_PREFIX = os.getenv('LOGIN_WHITELIST_PREFIX', '')
# 通配符匹配白名单(逗号分隔,支持 * 和 ? 通配符)
# * 匹配任意多个字符,? 匹配单个字符
# 示例:/job/*/send* 可匹配 /job/1/sendSms、/job/2/sendEmail
LOGIN_WHITELIST_WILDCARD = os.getenv('LOGIN_WHITELIST_WILDCARD', '')
# 是否启用白名单调试日志:True-打印匹配日志,False-不打印
LOGIN_WHITELIST_DEBUG = os.getenv('LOGIN_WHITELIST_DEBUG', 'False') == 'True'
# 是否在白名单模式下记录访问日志:True-记录,False-不记录
LOGIN_WHITELIST_LOG_ACCESS = os.getenv('LOGIN_WHITELIST_LOG_ACCESS', 'False') == 'True'
# ============================================================
# 万能验证码(仅 DEMO 模式)
# ============================================================
# 万能验证码(仅在 FLASK_DEMO=True 时生效,生产环境必须为空)
CAPTCHA_BYPASS_CODE = os.getenv('CAPTCHA_BYPASS_CODE', '')
+54
View File
@@ -0,0 +1,54 @@
"""
验证码配置模块
=============================================================
从环境变量读取验证码相关配置,支持字符集、长度、过期时间、防刷机制等自定义。
所有配置项均可在 .env 文件中调整,无需修改代码。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
# ============================================================
# 验证码基础配置
# ============================================================
# 验证码字符长度(4-6位,推荐4位)
# 4位:输入便捷,适合普通场景
# 6位:安全性较高,适合敏感操作
CAPTCHA_LENGTH = int(os.getenv('CAPTCHA_LENGTH', 4))
# 验证码过期时间(秒),默认5分钟
# 过期后验证码自动失效,需重新获取
CAPTCHA_EXPIRE = int(os.getenv('CAPTCHA_EXPIRE', 300))
# 验证码防刷窗口期(秒),默认60秒
# 在此时间窗口内,同一IP获取验证码次数受 CAPTCHA_RATE_LIMIT 限制
CAPTCHA_RATE_WINDOW = int(os.getenv('CAPTCHA_RATE_WINDOW', 60))
# 验证码防刷上限(窗口期内最大获取次数),默认10次
# 超过此次数后需等待窗口期结束才能再次获取
CAPTCHA_RATE_LIMIT = int(os.getenv('CAPTCHA_RATE_LIMIT', 10))
# 验证码字符集(去除易混淆字符:0/O/1/I/l/5/S/2/Z)
# 仅保留清晰易辨的字母和数字,提高用户输入正确率
CAPTCHA_CHARS = os.getenv('CAPTCHA_CHARS', 'ABCDEFGHJKLMNPQRSTUVWXYZ2346789')
# 验证码字体路径(相对于项目根目录)
CAPTCHA_FONT_PATH = os.getenv('CAPTCHA_FONT_PATH', 'static/fonts/Vera.ttf')
# 验证码图片宽度(像素)
CAPTCHA_IMAGE_WIDTH = int(os.getenv('CAPTCHA_IMAGE_WIDTH', 160))
# 验证码图片高度(像素)
CAPTCHA_IMAGE_HEIGHT = int(os.getenv('CAPTCHA_IMAGE_HEIGHT', 50))
# 验证码字体大小(像素)
CAPTCHA_FONT_SIZE = int(os.getenv('CAPTCHA_FONT_SIZE', 28))
# 干扰线数量
CAPTCHA_NOISE_LINES = int(os.getenv('CAPTCHA_NOISE_LINES', 6))
# 噪点数量
CAPTCHA_NOISE_DOTS = int(os.getenv('CAPTCHA_NOISE_DOTS', 30))
+171
View File
@@ -0,0 +1,171 @@
# +======================================================================
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
# +----------------------------------------------------------------------
# | Copyright (c) 2021-2026 一米阳光团队 版权所有
# +----------------------------------------------------------------------
# | 开源协议: Apache-2.0
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
# +----------------------------------------------------------------------
# | 官方网站: https://www.djangoadmin.cn
# +----------------------------------------------------------------------
# | 研发团队: 一米阳光团队 荣誉出品
# +======================================================================
"""
数据库配置模块
=============================================================
负责配置 MySQL 数据库连接及相关参数,包含连接池、SSL 加密等。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
from urllib.parse import quote_plus
from config.app import FLASK_SECRET_KEY, FLASK_UPLOAD_DIR
from config.redis import REDIS_URL
# ============================================================
# 数据库环境变量
# ============================================================
# 数据库驱动(mysql / pgsql / sqlite)
DB_DRIVER = os.getenv('DB_DRIVER', 'mysql')
# 数据库地址
DB_HOST = os.getenv('DB_HOST', '127.0.0.1')
# 数据库端口(MySQL默认3306,PostgreSQL默认5432)
DB_PORT = int(os.getenv('DB_PORT', 3306))
# 数据库名称
DB_DATABASE = os.getenv('DB_DATABASE', 'djangoadmin.flask.elevue')
# 数据库账号
DB_USERNAME = os.getenv('DB_USERNAME', 'root')
# 数据库密码
DB_PASSWORD = os.getenv('DB_PASSWORD', '')
# 数据表前缀(用于区分同一数据库中不同应用的数据表)
DB_PREFIX = os.getenv('DB_PREFIX', 'flask_')
# 是否开启调试模式:True-打印SQL日志,False-不打印
DB_DEBUG = os.getenv('DB_DEBUG', 'True') == 'True'
# 是否启用数据库SSL加密连接(生产环境建议开启,防止数据明文传输)
DB_SSL = os.getenv('DB_SSL', 'False') == 'True'
# SSL CA证书路径(用于验证服务端证书,留空则信任系统CA)
DB_SSL_CA = os.getenv('DB_SSL_CA', '')
# SSL 客户端证书路径(双向认证时使用)
DB_SSL_CERT = os.getenv('DB_SSL_CERT', '')
# SSL 客户端私钥路径(双向认证时使用)
DB_SSL_KEY = os.getenv('DB_SSL_KEY', '')
# ============================================================
# 连接池配置
# ============================================================
# 连接池常驻连接数(默认10,生产环境建议根据并发量调整)
DB_POOL_SIZE = int(os.getenv('DB_POOL_SIZE', 10))
# 超出pool_size后允许的最大额外连接(默认10,总连接数=pool_size+max_overflow)
DB_MAX_OVERFLOW = int(os.getenv('DB_MAX_OVERFLOW', 10))
# 连接自动回收时间/秒(默认1800,应小于MySQL的wait_timeout,防止"MySQL server has gone away")
DB_POOL_RECYCLE = int(os.getenv('DB_POOL_RECYCLE', 1800))
# 获取连接的超时时间/秒(默认30,超时抛出TimeoutError)
DB_POOL_TIMEOUT = int(os.getenv('DB_POOL_TIMEOUT', 30))
# 使用前是否检测连接存活(默认True,防止使用已被MySQL关闭的连接)
DB_POOL_PRE_PING = os.getenv('DB_POOL_PRE_PING', 'True') == 'True'
# 数据库连接URL(方便SQLAlchemy直接使用)
DATABASE_URL = f'mysql+pymysql://{quote_plus(DB_USERNAME)}:{quote_plus(DB_PASSWORD)}@{DB_HOST}:{DB_PORT}/{DB_DATABASE}'
def _build_engine_options():
"""
构建SQLAlchemy引擎选项
包含连接池配置和SSL加密配置。
连接池参数通过SQLALCHEMY_ENGINE_OPTIONS传递,
确保所有连接管理策略集中在一处。
"""
options = {
'pool_size': DB_POOL_SIZE,
'max_overflow': DB_MAX_OVERFLOW,
'pool_recycle': DB_POOL_RECYCLE,
'pool_timeout': DB_POOL_TIMEOUT,
'pool_pre_ping': DB_POOL_PRE_PING,
}
if DB_SSL:
ssl_config = {}
if DB_SSL_CA:
ssl_config['ca'] = DB_SSL_CA
if DB_SSL_CERT:
ssl_config['cert'] = DB_SSL_CERT
if DB_SSL_KEY:
ssl_config['key'] = DB_SSL_KEY
# 无证书路径时使用默认SSL(信任系统CA)
if not ssl_config:
ssl_config = True
options['connect_args'] = {'ssl': ssl_config}
return options
class DatabaseConfig:
"""
数据库配置类
包含 MySQL 连接、SQLAlchemy 设置、路径等配置
"""
# ============================================================
# 基础配置
# ============================================================
# 调试模式(从环境变量读取)
DEBUG = DB_DEBUG
# Flask 秘钥(用于 session 加密等)
# 启动时校验:未配置或过短则拒绝启动
if not FLASK_SECRET_KEY or len(FLASK_SECRET_KEY) < 16:
raise RuntimeError(
"FLASK_SECRET_KEY 未配置或过短!请在 .env 中设置至少16字节的强随机密钥。\n"
"生成方式:python -c \"import secrets; print(secrets.token_hex(32))\""
)
SECRET_KEY = FLASK_SECRET_KEY
# ============================================================
# CSRF 防护配置
# ============================================================
# 本项目使用 JWT(Authorization 头)认证,非 Cookie/Session,
# 天然防 CSRF,因此 WTForms CSRF 保护无需开启。
WTF_CSRF_CHECK_DEFAULT = False
WTF_CSRF_ENABLED = False
# ============================================================
# MySQL 数据库配置
# ============================================================
# 构建 MySQL 连接 URI(使用 PyMySQL 驱动)
SQLALCHEMY_DATABASE_URI = (
f'mysql+pymysql://{quote_plus(DB_USERNAME)}:{quote_plus(DB_PASSWORD)}@'
f'{DB_HOST}:{DB_PORT}/{DB_DATABASE}'
)
# 不追踪对象修改(提升性能)
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 是否打印 SQL 语句(调试模式下开启)
SQLALCHEMY_ECHO = DB_DEBUG
# 数据库连接引擎选项(连接池 + SSL加密)
SQLALCHEMY_ENGINE_OPTIONS = _build_engine_options()
# ============================================================
# 路径配置
# ============================================================
# 配置目录路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# 静态文件目录
STATIC_DIR = os.path.join(BASE_DIR, '../static')
# 模板文件目录
TEMPLATE_DIR = os.path.join(BASE_DIR, '../templates')
# 文件上传目录
FLASK_UPLOAD_DIR = FLASK_UPLOAD_DIR
# 模块测试入口
if __name__ == '__main__':
print(f"数据库连接: {DatabaseConfig.SQLALCHEMY_DATABASE_URI}")
print(f"调试模式: {DatabaseConfig.DEBUG}")
print(f"文件上传目录: {DatabaseConfig.FLASK_UPLOAD_DIR}")
+41
View File
@@ -0,0 +1,41 @@
"""
邮件配置模块
=============================================================
包含 SMTP 邮件发送相关的所有配置项。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
# ============================================================
# 邮件配置
# ============================================================
# 邮件发送方式(smtp / sendmail)
MAIL_MAILER = os.getenv('MAIL_MAILER', 'smtp')
# 邮件服务器地址(163邮箱:smtp.163.com,QQ邮箱:smtp.qq.com)
MAIL_SERVER = os.getenv('MAIL_SERVER', 'smtp.163.com')
# 邮件服务器端口(465-SSL加密,587-TLS加密)
MAIL_PORT = int(os.getenv('MAIL_PORT', 465))
# 是否启用SSL加密:True-启用,False-不启用
MAIL_USE_SSL = os.getenv('MAIL_USE_SSL', 'True') == 'True'
# 授权邮箱用户名(发送邮件的邮箱地址)
MAIL_USERNAME = os.getenv('MAIL_USERNAME', '')
# 授权邮箱授权码(不是登录密码,需在邮箱设置中获取)
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD', '')
# 邮件加密方式(ssl / tls)
MAIL_ENCRYPTION = os.getenv('MAIL_ENCRYPTION', '')
# 邮件发件人名称(显示在收件人处)
MAIL_FROM_NAME = os.getenv('MAIL_FROM_NAME', '')
# 邮件发件人地址(与MAIL_USERNAME保持一致)
MAIL_FROM_ADDRESS = os.getenv('MAIL_FROM_ADDRESS', '')
+39
View File
@@ -0,0 +1,39 @@
"""
Redis 缓存配置模块
=============================================================
包含 Redis 连接相关的所有配置项。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
# ============================================================
# 缓存配置(Redis)
# ============================================================
# 缓存服务地址
REDIS_HOST = os.getenv('REDIS_HOST', '127.0.0.1')
# 缓存服务端口(Redis默认6379)
REDIS_PORT = int(os.getenv('REDIS_PORT', 6379))
# 缓存服务密码(务必使用强密码)
REDIS_PASSWORD = os.getenv('REDIS_PASSWORD', '')
# 缓存库索引(0-15,不同索引用于不同业务)
REDIS_INDEX = int(os.getenv('REDIS_INDEX', 0))
# 是否需要进行用户认证:True-开启,False-关闭(生产环境必须开启)
REDIS_AUTH = os.getenv('REDIS_AUTH', 'True') == 'True'
# 是否对查询结果进行编码处理:True-自动解码,False-返回字节数据
REDIS_DECODE_RESPONSES = os.getenv('REDIS_DECODE_RESPONSES', 'True') == 'True'
# Redis连接URL(方便直接使用)
# 仅在 AUTH 开启且密码非空时才拼入密码,避免密码泄露到日志
if REDIS_AUTH and REDIS_PASSWORD:
REDIS_URL = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}'
else:
REDIS_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}'
+35
View File
@@ -0,0 +1,35 @@
"""
短信配置模块
=============================================================
包含阿里云短信服务相关的所有配置项。
依赖:config/__init__.py 中的 _load_env_file() 已提前加载 .env
"""
import os
# ============================================================
# 短信配置
# ============================================================
# 短信服务商(当前仅支持 aliyun,预留扩展)
SMS_PROVIDER = os.getenv('SMS_PROVIDER', 'aliyun')
# 阿里云 AccessKey ID(在阿里云控制台 > RAM访问控制 中获取)
SMS_ALIYUN_ACCESS_KEY_ID = os.getenv('SMS_ALIYUN_ACCESS_KEY_ID', '')
# 阿里云 AccessKey Secret(请妥善保管,不要提交到代码仓库)
SMS_ALIYUN_ACCESS_KEY_SECRET = os.getenv('SMS_ALIYUN_ACCESS_KEY_SECRET', '')
# 短信签名(需在阿里云控制台 > 短信服务 中审核通过)
SMS_ALIYUN_SIGN_NAME = os.getenv('SMS_ALIYUN_SIGN_NAME', '')
# 短信服务接入点(默认杭州区域,一般无需修改)
SMS_ALIYUN_ENDPOINT = os.getenv('SMS_ALIYUN_ENDPOINT', 'dysmsapi.aliyuncs.com')
# 连接超时(毫秒)- 建立连接的最大等待时间
SMS_ALIYUN_CONNECT_TIMEOUT = int(os.getenv('SMS_ALIYUN_CONNECT_TIMEOUT', 10000))
# 读取超时(毫秒)- 等待服务端响应的最大时间
SMS_ALIYUN_READ_TIMEOUT = int(os.getenv('SMS_ALIYUN_READ_TIMEOUT', 10000))