Phase 0 安全热修复 (CRITICAL): - 外部化微信 appid/secret 到 ERP__WECHAT__APPID/SECRET 环境变量 - 正确连接 HealthCrypto 到 ERP__HEALTH__AES_KEY/HMAC_KEY 环境变量 - 外部化小程序加密密钥到 TARO_APP_ENCRYPTION_KEY 环境变量 - 移除小程序 auth store 中的敏感信息 console.log Phase 1 安全加固: - 微信自动注册 display_name 添加 sanitize 防止 XSS - 测试数据库凭据改为从 TEST_DB_URL 环境变量读取 Phase 2 代码质量: - 提取 useThemeMode hook 消除 22 处重复暗色模式检测 - 提取共享健康常量到 constants/health.ts - 拆分 patient_service.rs 脱敏函数到 masking.rs - 移除未使用的 i18next/react-i18next 依赖 - 移除未使用的 api/errors.ts 和 erp-auth/anyhow 依赖 Phase 3 测试覆盖: - 新增 5 个患者模块集成测试 (CRUD/租户隔离/验证/软删除) Phase 4 跨平台一致性: - 统一小程序 Patient.birthday → birth_date 匹配后端 - 统一小程序 Appointment.time_slot → start_time/end_time 匹配后端 Phase 5 架构: - 微信登录添加多租户 TODO 注释 - 更新 wiki/infrastructure.md 环境变量文档
88 lines
2.2 KiB
Rust
88 lines
2.2 KiB
Rust
use serde::Deserialize;
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct AppConfig {
|
||
pub server: ServerConfig,
|
||
pub database: DatabaseConfig,
|
||
pub redis: RedisConfig,
|
||
pub jwt: JwtConfig,
|
||
pub auth: AuthConfig,
|
||
pub log: LogConfig,
|
||
pub cors: CorsConfig,
|
||
pub wechat: WechatConfig,
|
||
pub health: HealthConfig,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct ServerConfig {
|
||
pub host: String,
|
||
pub port: u16,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct DatabaseConfig {
|
||
pub url: String,
|
||
pub max_connections: u32,
|
||
pub min_connections: u32,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct RedisConfig {
|
||
pub url: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct JwtConfig {
|
||
pub secret: String,
|
||
pub access_token_ttl: String,
|
||
pub refresh_token_ttl: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct LogConfig {
|
||
pub level: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct AuthConfig {
|
||
pub super_admin_password: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct CorsConfig {
|
||
/// Comma-separated list of allowed origins.
|
||
/// Use "*" to allow all origins (development only).
|
||
pub allowed_origins: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct WechatConfig {
|
||
pub appid: String,
|
||
pub secret: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize)]
|
||
pub struct HealthConfig {
|
||
/// AES-256 密钥 (64 字符 hex 编码,32 字节)
|
||
pub aes_key: String,
|
||
/// HMAC-SHA256 密钥 (64 字符 hex 编码,32 字节)
|
||
pub hmac_key: String,
|
||
}
|
||
|
||
impl AppConfig {
|
||
pub fn load() -> anyhow::Result<Self> {
|
||
let config = config::Config::builder()
|
||
.add_source(config::File::with_name("config/default"))
|
||
.add_source(config::Environment::with_prefix("ERP").separator("__"))
|
||
.build()?;
|
||
let app_config: Self = config.try_deserialize()?;
|
||
|
||
// 安全检查:禁止在生产使用默认 JWT 密钥
|
||
if app_config.jwt.secret == "change-me-in-production" {
|
||
tracing::warn!("⚠️ JWT 密钥使用默认值,请通过 ERP__JWT__SECRET 环境变量设置安全密钥");
|
||
}
|
||
|
||
Ok(app_config)
|
||
}
|
||
}
|