第一次提交
This commit is contained in:
215
scripts/setup_env.py
Normal file
215
scripts/setup_env.py
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
环境变量配置和验证脚本
|
||||
自动生成安全的随机密钥并验证配置
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import secrets
|
||||
import getpass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_secret_key(length=32):
|
||||
"""生成安全的随机密钥"""
|
||||
return secrets.token_urlsafe(length)
|
||||
|
||||
|
||||
def generate_hex_key(length=32):
|
||||
"""生成十六进制随机密钥"""
|
||||
return secrets.token_hex(length)
|
||||
|
||||
|
||||
def check_env_vars():
|
||||
"""检查必需的环境变量"""
|
||||
print("🔍 检查环境变量配置...")
|
||||
print("-" * 60)
|
||||
|
||||
required_vars = {
|
||||
'SECRET_KEY': '应用密钥(用于会话加密)',
|
||||
'AUTH_SECRET_KEY': '认证密钥(用于API签名)',
|
||||
'DATABASE_URL': '数据库连接URL'
|
||||
}
|
||||
|
||||
missing_vars = []
|
||||
weak_keys = []
|
||||
|
||||
for var_name, description in required_vars.items():
|
||||
value = os.environ.get(var_name)
|
||||
if not value:
|
||||
print(f"❌ {var_name:20s} - 未设置 ({description})")
|
||||
missing_vars.append(var_name)
|
||||
else:
|
||||
print(f"✅ {var_name:20s} - 已设置")
|
||||
# 检查密钥强度
|
||||
if 'KEY' in var_name:
|
||||
if len(value) < 32:
|
||||
print(f"⚠️ {var_name:20s} - 密钥长度不足32字符 (当前: {len(value)})")
|
||||
weak_keys.append(var_name)
|
||||
else:
|
||||
print(f"✅ {var_name:20s} - 密钥长度符合要求")
|
||||
|
||||
print("-" * 60)
|
||||
|
||||
if missing_vars:
|
||||
print(f"\n❌ 发现 {len(missing_vars)} 个未设置的环境变量")
|
||||
return False
|
||||
elif weak_keys:
|
||||
print(f"\n⚠️ 发现 {len(weak_keys)} 个强度不足的密钥")
|
||||
return False
|
||||
else:
|
||||
print("\n✅ 所有必需的环境变量已正确配置")
|
||||
return True
|
||||
|
||||
|
||||
def generate_env_file():
|
||||
"""生成 .env 文件"""
|
||||
print("\n🚀 生成 .env 文件...")
|
||||
print("-" * 60)
|
||||
|
||||
# 收集用户输入
|
||||
database_url = input("数据库URL (mysql://user:pass@localhost:3306/dbname): ").strip()
|
||||
if not database_url:
|
||||
print("❌ 数据库URL不能为空")
|
||||
return False
|
||||
|
||||
frontend_domain = input("前端域名 (your-domain.com): ").strip()
|
||||
admin_email = input("管理员邮箱 (admin@yourcompany.com): ").strip()
|
||||
|
||||
# 生成随机密钥
|
||||
secret_key = generate_secret_key(32)
|
||||
auth_secret_key = generate_secret_key(32)
|
||||
|
||||
# 生成 .env 文件内容
|
||||
env_content = f"""# KaMiXiTong 生产环境配置
|
||||
# 生成时间: {__import__('datetime').datetime.now().isoformat()}
|
||||
|
||||
# ==========================================
|
||||
# 🔐 安全配置
|
||||
# ==========================================
|
||||
SECRET_KEY={secret_key}
|
||||
AUTH_SECRET_KEY={auth_secret_key}
|
||||
|
||||
# ==========================================
|
||||
# 🗄️ 数据库配置
|
||||
# ==========================================
|
||||
DATABASE_URL={database_url}
|
||||
DB_POOL_SIZE=20
|
||||
DB_MAX_OVERFLOW=30
|
||||
DB_POOL_RECYCLE=3600
|
||||
DB_POOL_TIMEOUT=30
|
||||
|
||||
# ==========================================
|
||||
# 🌐 系统配置
|
||||
# ==========================================
|
||||
SITE_NAME=KaMiXiTong软件授权管理系统
|
||||
ADMIN_EMAIL={admin_email}
|
||||
FRONTEND_DOMAIN={frontend_domain}
|
||||
API_VERSION=v1
|
||||
|
||||
# ==========================================
|
||||
# 🔒 安全策略
|
||||
# ==========================================
|
||||
SESSION_COOKIE_SECURE=true
|
||||
SESSION_COOKIE_HTTPONLY=true
|
||||
SESSION_COOKIE_SAMESITE=Lax
|
||||
SESSION_LIFETIME_HOURS=24
|
||||
REMEMBER_COOKIE_DURATION=30
|
||||
REMEMBER_COOKIE_SECURE=true
|
||||
MAX_FAILED_ATTEMPTS=5
|
||||
LOCKOUT_MINUTES=10
|
||||
MAX_UNBIND_TIMES=3
|
||||
|
||||
# ==========================================
|
||||
# 💾 缓存配置
|
||||
# ==========================================
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# ==========================================
|
||||
# 📝 日志配置
|
||||
# ==========================================
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FILE=logs/kamaxitong.log
|
||||
|
||||
# ==========================================
|
||||
# 📦 文件上传
|
||||
# ==========================================
|
||||
MAX_CONTENT_LENGTH=52428800
|
||||
UPLOAD_FOLDER=static/uploads
|
||||
|
||||
# ==========================================
|
||||
# 🏷️ 卡密配置
|
||||
# ==========================================
|
||||
LICENSE_KEY_LENGTH=32
|
||||
TRIAL_PREFIX=TRIAL_
|
||||
OFFLINE_CACHE_DAYS=7
|
||||
|
||||
# ==========================================
|
||||
# 🌍 环境标识
|
||||
# ==========================================
|
||||
FLASK_ENV=production
|
||||
DEBUG=false
|
||||
|
||||
# ==========================================
|
||||
# 💳 支付配置(可选)
|
||||
# ==========================================
|
||||
PAYMENT_ENABLED=false
|
||||
"""
|
||||
|
||||
# 写入文件
|
||||
env_file = Path('.env')
|
||||
try:
|
||||
with open(env_file, 'w', encoding='utf-8') as f:
|
||||
f.write(env_content)
|
||||
print(f"✅ .env 文件已生成: {env_file.absolute()}")
|
||||
print(f"\n⚠️ 请妥善保管此文件,不要提交到版本控制系统")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ 生成 .env 文件失败: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("=" * 60)
|
||||
print("🔧 KaMiXiTong 环境变量配置工具")
|
||||
print("=" * 60)
|
||||
|
||||
# 检查是否已存在 .env 文件
|
||||
env_file = Path('.env')
|
||||
if env_file.exists():
|
||||
print(f"\n⚠️ 发现已存在的 .env 文件")
|
||||
overwrite = input("是否覆盖?(y/N): ").strip().lower()
|
||||
if overwrite != 'y':
|
||||
print("操作已取消")
|
||||
return
|
||||
|
||||
# 生成 .env 文件
|
||||
if not generate_env_file():
|
||||
sys.exit(1)
|
||||
|
||||
# 重新加载环境变量
|
||||
print("\n🔄 重新加载环境变量...")
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
# 验证配置
|
||||
if not check_env_vars():
|
||||
print("\n❌ 环境变量配置不完整,请检查后重新运行")
|
||||
sys.exit(1)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ 环境变量配置完成!")
|
||||
print("=" * 60)
|
||||
print("\n📋 下一步操作:")
|
||||
print("1. 运行数据库迁移: flask db upgrade")
|
||||
print("2. 启动应用: flask run")
|
||||
print("3. 访问健康检查: curl http://localhost:5000/api/v1/health")
|
||||
print("\n🔐 安全提醒:")
|
||||
print("- 妥善保管 .env 文件,不要提交到版本控制")
|
||||
print("- 定期更换密钥")
|
||||
print("- 确保生产环境启用HTTPS")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user