12-配置管理
Python 3.11+ | Flask 3.x
本章讲解 Flask 配置管理的完整体系:从基础用法到多环境分离,再到生产级安全实践。
第一部分:配置基础(L1)
1.1 实际场景
你的 Flask 应用需要管理数据库连接、密钥、调试开关等参数。硬编码在代码中会导致环境切换困难、密钥泄露等问题。
问题:Flask 如何统一管理应用配置?
1.2 app.config 是什么
app.config 是 Flask 应用的核心配置容器,本质是一个继承自 dict 的类字典对象,但具有额外功能:
app.config 结构:
┌─────────────────────────────────────────────────────────────┐
│ Flask Config 对象 │
├─────────────────────────────────────────────────────────────┤
│ │
│ • 继承自 dict,支持所有字典操作 │
│ • 自动加载 Flask 内置默认配置 │
│ • 支持多种加载方式:文件、对象、环境变量、JSON │
│ • 配置键约定:全大写字母(如 SECRET_KEY、DEBUG) │
│ │
│ 工作流程: │
│ 1. 创建 app 时 → 加载内置默认配置 │
│ 2. 调用 from_object → 从 Python 对象加载 │
│ 3. 调用 from_envvar → 从环境变量加载 │
│ 4. 运行时可直接修改 → app.config['KEY'] = value │
│ │
└─────────────────────────────────────────────────────────────┘1.3 基本用法:直接赋值
python
# app_simple.py
from flask import Flask
app: Flask = Flask(__name__)
# 直接设置配置项
app.config["DEBUG"] = True
app.config["SECRET_KEY"] = "dev-secret-key-change-in-production"
app.config["DATABASE_URI"] = "sqlite:///app.db"
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 # 16MB
# 读取配置
secret: str = app.config["SECRET_KEY"]
debug_mode: bool = app.config.get("DEBUG", False)| 代码片段 | 含义 | 说明 |
|---|---|---|
app.config["KEY"] = value | 设置配置项 | 键名约定全大写 |
app.config["KEY"] | 获取配置项 | 不存在时抛 KeyError |
app.config.get("KEY", default) | 安全获取 | 不存在时返回默认值 |
注意:直接赋值适合简单场景,但生产应用推荐使用配置对象或配置文件。
1.4 从 Python 对象加载:from_object
from_object 是 Flask 最常用的配置加载方式,从 Python 模块或类中加载所有大写字母开头的属性:
python
# config.py
class Config:
"""基础配置类"""
SECRET_KEY: str = "default-secret-key"
DEBUG: bool = False
TESTING: bool = False
DATABASE_URI: str = "sqlite:///app.db"
MAX_CONTENT_LENGTH: int = 16 * 1024 * 1024
class DevelopmentConfig(Config):
"""开发环境配置"""
DEBUG: bool = True
DATABASE_URI: str = "sqlite:///dev.db"
class ProductionConfig(Config):
"""生产环境配置"""
SECRET_KEY: str = "production-secret-key-from-env"
DATABASE_URI: str = "postgresql://user:pass@db-server/prod_db"python
# app_from_object.py
from flask import Flask
from config import DevelopmentConfig
app: Flask = Flask(__name__)
# 从类加载配置(只加载大写字母开头的属性)
app.config.from_object(DevelopmentConfig)
# 验证加载结果
print(app.config["DEBUG"]) # True
print(app.config["DATABASE_URI"]) # sqlite:///dev.db| 代码片段 | 含义 |
|---|---|
from_object(DevelopmentConfig) | 从类加载,继承链上的属性也会加载 |
from_object("config.ProductionConfig") | 从字符串路径加载,支持动态导入 |
from_object(config_module) | 从模块对象加载,加载模块内所有大写属性 |
1.5 从环境变量加载:from_envvar
python
# app_from_envvar.py
import os
from flask import Flask
app: Flask = Flask(__name__)
# 方式一:指定环境变量名,该变量值为配置文件路径
# 假设环境变量 FLASK_CONFIG_FILE=/etc/myapp/config.py
app.config.from_envvar("FLASK_CONFIG_FILE")
# 方式二:设置 silent=True,环境变量不存在时不报错
app.config.from_envvar("FLASK_CONFIG_FILE", silent=True)
# 方式三:结合默认配置
app.config.from_object("config.DefaultConfig")
app.config.from_envvar("FLASK_CONFIG_FILE", silent=True) # 覆盖默认配置bash
# 终端设置环境变量
export FLASK_CONFIG_FILE=/path/to/config.py
flask run第二部分:多环境配置(L1)
2.1 开发/测试/生产环境分离
不同环境需要不同的配置参数:
环境配置对比:
┌─────────────────┬──────────────────┬──────────────────┬──────────────────┐
│ 配置项 │ 开发环境 │ 测试环境 │ 生产环境 │
├─────────────────┼──────────────────┼──────────────────┼──────────────────┤
│ DEBUG │ True │ False │ False │
│ TESTING │ False │ True │ False │
│ DATABASE_URI │ sqlite:///dev.db │ sqlite:///test.db│ postgresql://... │
│ SECRET_KEY │ dev-key │ test-key │ 加密存储的密钥 │
│ LOG_LEVEL │ DEBUG │ INFO │ WARNING │
│ MAIL_SERVER │ localhost │ localhost │ smtp.company.com │
│ CACHE_TYPE │ SimpleCache │ SimpleCache │ RedisCache │
└─────────────────┴──────────────────┴──────────────────┴──────────────────┘2.2 配置类模式
python
# config.py
import os
class Config:
"""基础配置——所有环境共有的配置"""
# 安全配置
SECRET_KEY: str = os.environ.get("SECRET_KEY", "dev-secret-key")
# 数据库
SQLALCHEMY_DATABASE_URI: str = os.environ.get(
"DATABASE_URL", "sqlite:///app.db"
)
SQLALCHEMY_TRACK_MODIFICATIONS: bool = False
# 文件上传
MAX_CONTENT_LENGTH: int = 16 * 1024 * 1024 # 16MB
UPLOAD_FOLDER: str = os.path.join(os.path.dirname(__file__), "uploads")
# 分页
ITEMS_PER_PAGE: int = 20
# 缓存
CACHE_TYPE: str = "SimpleCache"
CACHE_DEFAULT_TIMEOUT: int = 300
@staticmethod
def init_app(app) -> None:
"""每个环境共享的初始化逻辑"""
pass
class DevelopmentConfig(Config):
"""开发环境"""
DEBUG: bool = True
TESTING: bool = False
SQLALCHEMY_DATABASE_URI: str = os.environ.get(
"DEV_DATABASE_URL", "sqlite:///dev.db"
)
CACHE_TYPE: str = "SimpleCache"
MAIL_SERVER: str = "localhost"
MAIL_PORT: int = 25
MAIL_USE_TLS: bool = False
class TestingConfig(Config):
"""测试环境"""
DEBUG: bool = False
TESTING: bool = True
SQLALCHEMY_DATABASE_URI: str = os.environ.get(
"TEST_DATABASE_URL", "sqlite:///test.db"
)
WTF_CSRF_ENABLED: bool = False # 测试时禁用 CSRF
class ProductionConfig(Config):
"""生产环境"""
DEBUG: bool = False
TESTING: bool = False
SQLALCHEMY_DATABASE_URI: str = os.environ.get("DATABASE_URL", "")
CACHE_TYPE: str = "RedisCache"
CACHE_REDIS_URL: str = os.environ.get("REDIS_URL", "redis://localhost:6379")
@staticmethod
def init_app(app) -> None:
"""生产环境额外初始化"""
Config.init_app(app)
# 可在此添加日志配置、错误监控等
# 配置映射字典,方便动态选择
config_map: dict[str, type[Config]] = {
"development": DevelopmentConfig,
"testing": TestingConfig,
"production": ProductionConfig,
"default": DevelopmentConfig,
}2.3 工厂模式 + 配置类结合
python
# app/__init__.py
import os
from flask import Flask
from config import config_map
def create_app(config_name: str | None = None) -> Flask:
"""应用工厂函数"""
# 未指定时从环境变量读取,默认为 development
if config_name is None:
config_name = os.environ.get("FLASK_ENV", "development")
app: Flask = Flask(__name__)
# 加载对应配置类
config_class: type[config_map["default"]] = config_map.get(
config_name, config_map["default"]
)
app.config.from_object(config_class)
# 执行配置类中的初始化钩子
config_class.init_app(app)
# 注册蓝图
from app.main import main as main_blueprint
from app.auth import auth as auth_blueprint
app.register_blueprint(main_blueprint)
app.register_blueprint(auth_blueprint, url_prefix="/auth")
# 注册扩展
from app.extensions import db, migrate, login_manager
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
return apppython
# run.py
from app import create_app
# 根据环境变量自动选择配置
app = create_app()
if __name__ == "__main__":
app.run()bash
# 切换环境
export FLASK_ENV=development && python run.py
export FLASK_ENV=production && python run.py第三部分:L2 实践层
3.1 dotenv 文件(Flask 3.x 原生支持)
Flask 3.x 内置对 .env 和 .flaskenv 文件的支持,通过 python-dotenv 加载:
dotenv 加载流程:
┌─────────────────────────────────────────────────────────────┐
│ Flask 启动时环境变量加载顺序 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 系统环境变量(优先级最高) │
│ ↓ │
│ 2. 项目根目录的 .env 文件 │
│ ↓ │
│ 3. 项目根目录的 .flaskenv 文件(仅 Flask 相关) │
│ ↓ │
│ 4. 代码中的默认值(优先级最低) │
│ │
│ 注意:已存在的环境变量不会被 .env 文件覆盖 │
│ │
└─────────────────────────────────────────────────────────────┘ini
# .env —— 开发环境敏感配置(不提交到 Git)
SECRET_KEY=your-super-secret-key-here
DATABASE_URL=postgresql://user:password@localhost/dev_db
REDIS_URL=redis://localhost:6379/0
MAIL_PASSWORD=email-app-password
FLASK_APP=run.py
FLASK_ENV=developmentini
# .flaskenv —— Flask CLI 相关配置(可以提交到 Git)
FLASK_APP=run.py
FLASK_ENV=development
FLASK_DEBUG=1python
# app/__init__.py
import os
from flask import Flask
from dotenv import load_dotenv
# 显式加载 .env(Flask CLI 自动加载,但程序运行时需手动加载)
dotenv_path: str = os.path.join(os.path.dirname(__file__), "..", ".env")
load_dotenv(dotenv_path)
def create_app() -> Flask:
app: Flask = Flask(__name__)
# 从环境变量读取敏感配置
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DATABASE_URL")
return app重要:
.env文件必须添加到.gitignore,防止敏感信息泄露。
3.2 instance folders(实例文件夹)
Flask 提供 instance folder 机制,用于存放部署时特定的配置文件:
instance folder 位置:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 相对路径模式(默认): │
│ myapp/ │
│ ├── app/ │
│ │ └── __init__.py ← app.instance_path 指向 instance/ │
│ └── instance/ │
│ └── config.py ← 部署时创建的实例配置 │
│ │
│ 绝对路径模式: │
│ myapp/ │
│ ├── app/ │
│ │ └── __init__.py ← instance_relative_config=True │
│ └── /var/www/myapp-instance/ │
│ └── config.py │
│ │
└─────────────────────────────────────────────────────────────┘python
# app/__init__.py
from flask import Flask
# instance_relative_config=True 使相对路径指向 instance/ 目录
app: Flask = Flask(__name__, instance_relative_config=True)
# 加载默认配置
app.config.from_object("config.DefaultConfig")
# 尝试从 instance 文件夹加载(不存在时不报错)
app.config.from_pyfile("config.py", silent=True)python
# instance/config.py —— 部署时手动创建
SECRET_KEY = "production-secret-from-instance-folder"
SQLALCHEMY_DATABASE_URI = "postgresql://user:pass@localhost/prod_db"3.3 环境变量 vs 配置文件 vs 代码
配置方式选择指南:
┌──────────────────────┬──────────────┬──────────────┬──────────────┐
│ 配置方式 │ 适用场景 │ 优点 │ 缺点 │
├──────────────────────┼──────────────┼──────────────┼──────────────┤
│ 环境变量 │ 敏感信息 │ 不入库、安全 │ 管理复杂 │
│ (.env / 系统变量) │ 部署差异 │ 平台通用 │ IDE 不支持 │
├──────────────────────┼──────────────┼──────────────┼──────────────┤
│ 配置类/文件 │ 结构配置 │ 版本可控 │ 不能存密钥 │
│ (config.py) │ 默认值 │ IDE 支持好 │ 需区分环境 │
├──────────────────────┼──────────────┼──────────────┼──────────────┤
│ instance/config.py │ 部署时配置 │ 代码分离 │ 部署步骤多 │
│ │ 服务器特定 │ 不入库 │ 难以自动化 │
├──────────────────────┼──────────────┼──────────────┼──────────────┤
│ 密钥管理服务 │ 生产密钥 │ 最安全 │ 依赖外部服务 │
│ (Vault/SecretsMgr) │ 多实例部署 │ 集中管理 │ 增加复杂度 │
└──────────────────────┴──────────────┴──────────────┴──────────────┘3.4 最佳实践
推荐配置架构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 第 1 层:config.py(提交到 Git) │
│ ├── 配置类定义(开发/测试/生产) │
│ ├── 非敏感默认值 │
│ └── 配置选择逻辑 │
│ ↓ │
│ 第 2 层:.env(不提交,.gitignore) │
│ ├── 敏感配置(SECRET_KEY、数据库密码) │
│ ├── 环境特定变量 │
│ └── 开发便利变量(FLASK_APP、FLASK_DEBUG) │
│ ↓ │
│ 第 3 层:instance/config.py(部署时手动创建) │
│ ├── 服务器特定配置 │
│ ├── 生产覆盖值 │
│ └── 可选,与环境变量互补 │
│ │
│ 配置加载优先级: │
│ 环境变量 > .env > instance/config.py > config.py 默认值 │
│ │
└─────────────────────────────────────────────────────────────┘| 做法 | 原因 | 示例 |
|---|---|---|
| 敏感信息只放环境变量 | 避免提交到版本控制 | os.environ.get("SECRET_KEY") |
| 配置类存非敏感默认值 | 版本可控,文档化 | SQLALCHEMY_TRACK_MODIFICATIONS = False |
.env 加入 .gitignore | 防止密钥泄露 | .env 写入 .gitignore |
提供 .env.example | 开发者知道需要哪些变量 | 提交模板,不提交真实值 |
| 生产使用密钥管理服务 | 集中管理、轮换、审计 | AWS Secrets Manager, HashiCorp Vault |
3.5 常见陷阱
陷阱一:密钥泄露
python
# ❌ 错误:硬编码密钥到代码
app.config["SECRET_KEY"] = "super-secret-key-123"
app.config["DATABASE_URI"] = "mysql://root:password123@localhost/db"
# ✅ 正确:从环境变量读取
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
app.config["DATABASE_URI"] = os.environ.get("DATABASE_URL")陷阱二:环境混淆
python
# ❌ 错误:没有环境区分,生产用 DEBUG=True
app.config["DEBUG"] = True # 生产环境会暴露堆栈信息
# ✅ 正确:通过配置类隔离
# config.py 中 ProductionConfig.DEBUG = False陷阱三:配置加载顺序错误
python
# ❌ 错误:from_pyfile 在 from_object 之前,默认值覆盖了实例配置
app.config.from_pyfile("config.py", silent=True)
app.config.from_object(DevelopmentConfig) # 会覆盖 from_pyfile 的值
# ✅ 正确:先加载默认,再用实例配置覆盖
app.config.from_object(DevelopmentConfig)
app.config.from_pyfile("config.py", silent=True) # 后加载的优先级高陷阱四:.env 文件提交到 Git
gitignore
# .gitignore
.env # 包含真实密钥
.env.local # 本地覆盖
*.pyc
__pycache__/
instance/ # 实例文件夹也建议忽略bash
# 提供模板供团队使用
# .env.example
SECRET_KEY=change-me-to-random-string
DATABASE_URL=sqlite:///dev.db
MAIL_PASSWORD=your-email-app-password第四部分:L3 专家层
4.1 Flask 内置配置值详解
Flask 内置配置分类:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 安全类: │
│ ├── SECRET_KEY Session/CSRF 签名密钥 │
│ ├── SESSION_COOKIE_* Session Cookie 各项属性 │
│ └── MAX_CONTENT_LENGTH 最大请求体大小 │
│ │
│ 应用类: │
│ ├── DEBUG 调试模式(启用交互调试器) │
│ ├── TESTING 测试模式(异常不传播) │
│ └── ENV / FLASK_ENV 环境标识 │
│ │
│ 服务器类: │
│ ├── SERVER_NAME 服务器名称和端口 │
│ ├── PREFERRED_URL_SCHEME URL 生成时使用的协议 │
│ └── PERMANENT_SESSION_LIFETIME Session 有效期 │
│ │
│ 模板/静态文件: │
│ ├── TEMPLATE_FOLDER 模板目录路径 │
│ ├── STATIC_FOLDER 静态文件目录路径 │
│ └── STATIC_URL_PATH 静态文件 URL 前缀 │
│ │
└─────────────────────────────────────────────────────────────┘SECRET_KEY
python
# 生成安全的随机密钥
# app/key_gen.py
import secrets
# 生成 32 字节(256 位)的随机密钥
secret_key: str = secrets.token_hex(32)
print(secret_key)
# 输出示例:a3f2c8d1e9b745f6a0c2d4e8b1f3a5c7d9e0b2a4f6c8d0e2b4a6c8d0e2b4a6c8| 代码片段 | 含义 |
|---|---|
secrets.token_hex(32) | 生成 64 字符十六进制随机字符串 |
secrets.token_urlsafe(32) | 生成 URL 安全的 Base64 字符串 |
os.urandom(32) | 生成原始字节,适合底层使用 |
警告:不要使用
random模块生成密钥,它不是密码学安全的。
SESSION_COOKIE_* 配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
SESSION_COOKIE_NAME | "session" | Cookie 名称 |
SESSION_COOKIE_DOMAIN | None | Cookie 域名,None 为当前域名 |
SESSION_COOKIE_PATH | None | Cookie 路径,None 为应用根路径 |
SESSION_COOKIE_HTTPONLY | True | 阻止 JavaScript 访问(防 XSS) |
SESSION_COOKIE_SECURE | False | 仅 HTTPS 传输(生产应设为 True) |
SESSION_COOKIE_SAMESITE | None | 防 CSRF,推荐设为 "Lax" 或 "Strict" |
PERMANENT_SESSION_LIFETIME | timedelta(days=31) | 永久 Session 过期时间 |
python
# app/config_security.py
from datetime import timedelta
from flask import Flask
app: Flask = Flask(__name__)
# 生产级 Session Cookie 配置
app.config["SESSION_COOKIE_HTTPONLY"] = True
app.config["SESSION_COOKIE_SECURE"] = True # 仅 HTTPS
app.config["SESSION_COOKIE_SAMESITE"] = "Lax" # 防 CSRF
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(hours=2)MAX_CONTENT_LENGTH
python
# 限制上传文件大小
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 # 16MB
# 超过限制时,Flask 自动返回 413 Request Entity Too Large
# 无需手动检查4.2 配置加载优先级链
配置加载优先级(从高到低):
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 运行时直接赋值(最高优先级) │ │
│ │ app.config["KEY"] = "override-value" │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 2. from_envvar() │ │
│ │ app.config.from_envvar("APP_CONFIG_FILE") │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 3. from_pyfile() │ │
│ │ app.config.from_pyfile("instance/config.py") │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 4. from_object() │ │
│ │ app.config.from_object(ProductionConfig) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 5. Flask 内置默认值(最低优先级) │ │
│ │ app 创建时自动加载 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 原则:后加载的覆盖先加载的 │
│ │
└─────────────────────────────────────────────────────────────┘python
# app/config_priority_demo.py
from flask import Flask
app: Flask = Flask(__name__, instance_relative_config=True)
# 加载顺序演示
# 第 1 步:Flask 内置默认值(DEBUG=False, SECRET_KEY=None 等)
# 第 2 步:从配置类加载默认值
app.config.from_object("config.DefaultConfig")
# 第 3 步:从实例文件夹加载(覆盖第 2 步)
app.config.from_pyfile("config.py", silent=True)
# 第 4 步:从环境变量加载(覆盖第 3 步)
app.config.from_envvar("APP_CONFIG_FILE", silent=True)
# 第 5 步:运行时直接赋值(最高优先级)
app.config["SPECIAL_FLAG"] = True4.3 敏感配置的安全管理
生产环境密钥管理架构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 方案一:环境变量(最常用) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 部署平台:Docker / K8s / Heroku / AWS │ │
│ │ 做法:在部署平台界面设置环境变量 │ │
│ │ 代码:os.environ.get("SECRET_KEY") │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 方案二:密钥管理服务(企业级) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ AWS Secrets Manager / HashiCorp Vault / │ │
│ │ Azure Key Vault / GCP Secret Manager │ │
│ │ 做法:应用启动时从服务拉取密钥 │ │
│ │ 优势:自动轮换、审计日志、细粒度权限 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 方案三:加密配置文件 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 做法:配置文件加密存储,启动时解密 │ │
│ │ 工具:sops + AWS KMS / GPG │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘HashiCorp Vault 集成示例
python
# app/vault_config.py
import os
import hvac
def load_secrets_from_vault(vault_addr: str, vault_token: str) -> dict[str, str]:
"""从 Vault 加载密钥"""
client: hvac.Client = hvac.Client(url=vault_addr, token=vault_token)
# 读取密钥(Vault KV v2 引擎)
secret_data: dict[str, str] = client.secrets.kv.v2.read_secret_version(
path="flask-app",
mount_point="secret",
)["data"]["data"]
return secret_data
def apply_vault_config(app) -> None:
"""将 Vault 密钥应用到 Flask 配置"""
vault_addr: str = os.environ.get("VAULT_ADDR", "https://vault.company.com")
vault_token: str = os.environ.get("VAULT_TOKEN")
if vault_token:
secrets: dict[str, str] = load_secrets_from_vault(vault_addr, vault_token)
app.config["SECRET_KEY"] = secrets.get("SECRET_KEY")
app.config["SQLALCHEMY_DATABASE_URI"] = secrets.get("DATABASE_URL")
app.config["MAIL_PASSWORD"] = secrets.get("MAIL_PASSWORD")AWS Secrets Manager 集成示例
python
# app/aws_config.py
import json
import os
import boto3
from botocore.exceptions import ClientError
def get_secret(secret_name: str, region: str = "us-east-1") -> dict[str, str]:
"""从 AWS Secrets Manager 获取密钥"""
client = boto3.client("secretsmanager", region_name=region)
try:
response = client.get_secret_value(SecretId=secret_name)
secret_string: str = response["SecretString"]
return json.loads(secret_string)
except ClientError as e:
# 生产环境建议失败快速(fail-fast)
raise RuntimeError(f"无法加载密钥 {secret_name}: {e}") from e
def apply_aws_secrets(app) -> None:
"""将 AWS 密钥应用到 Flask 配置"""
secret_name: str = os.environ.get("AWS_SECRET_NAME", "flask-app/prod")
secrets: dict[str, str] = get_secret(secret_name)
app.config["SECRET_KEY"] = secrets["SECRET_KEY"]
app.config["SQLALCHEMY_DATABASE_URI"] = secrets["DATABASE_URL"]4.4 知识关联图
配置管理知识关联:
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌───────────────────┐ │
│ │ 环境变量管理 │ │
│ │ (os.environ) │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ↓ ↓ ↓ │
│ ┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ python-dotenv │ │ app.config │ │ instance folder │ │
│ │ (.env 文件) │ │ (配置容器) │ │ (部署时配置) │ │
│ └────────┬─────────┘ └──────┬───────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └──────────┬───────┘ │ │
│ ↓ ↓ │
│ ┌───────────────────┐ ┌──────────────────┐ │
│ │ 配置类模式 │ │ 密钥管理服务 │ │
│ │ (Dev/Test/Prod) │ │ (Vault/AWS) │ │
│ └─────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │
│ ↓ ↓ │
│ ┌───────────────────┐ ┌──────────────────┐ │
│ │ 应用工厂模式 │ │ 安全最佳实践 │ │
│ │ (create_app) │ │ (HTTPS/Cookie) │ │
│ └───────────────────┘ └──────────────────┘ │
│ │
│ 前置知识:字典操作、环境变量、Python 模块导入 │
│ 进阶扩展:CI/CD 配置注入、基础设施即代码 (Terraform) │
│ │
└─────────────────────────────────────────────────────────────┘本章总结
配置管理全景:
┌─────────────────────────────────────────────────────────────┐
│ │
│ L1 基础: │
│ ├── app.config 是类字典对象,管理 Flask 所有配置 │
│ ├── 直接赋值:app.config['KEY'] = value │
│ ├── from_object():从 Python 类/模块加载 │
│ └── from_envvar():从环境变量指定的文件加载 │
│ │
│ L1 多环境: │
│ ├── 配置类模式:DevelopmentConfig / TestingConfig / Prod │
│ ├── 工厂模式 + 配置类:create_app(config_name) │
│ └── config_map 字典实现动态选择 │
│ │
│ L2 实践: │
│ ├── .env 文件(Flask 3.x 原生支持) │
│ ├── instance/config.py(部署时特定配置) │
│ ├── 环境变量存密钥,配置类存默认值 │
│ └── 避免:硬编码密钥、DEBUG=True 上生产、提交 .env │
│ │
│ L3 专家: │
│ ├── 配置加载优先级:运行时 > from_envvar > from_pyfile │
│ │ > from_object > 内置默认 │
│ ├── SESSION_COOKIE_SECURE=True, SAMESITE=Lax 生产必设 │
│ └── 密钥管理:Vault / AWS Secrets Manager / 加密文件 │
│ │
│ 核心原则: │
│ 代码存结构,环境存差异,密钥存服务 │
│ │
└─────────────────────────────────────────────────────────────┘