/** * 微信服务号配置检查脚本 * * 功能: * 1. 检查必需的环境变量是否配置 * 2. 验证Token和EncodingAESKey长度 * 3. 测试签名生成功能 * 4. 输出配置信息(用于微信公众平台) */ import dotenv from 'dotenv'; import crypto from 'crypto'; import path from 'path'; import { fileURLToPath } from 'url'; // 获取当前文件目录 const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // 加载.env文件 dotenv.config({ path: path.resolve(__dirname, '../../../.env') }); console.log('🔧 微信服务号配置检查'); console.log('=' .repeat(60)); console.log(''); // ==================== 1. 检查必需的环境变量 ==================== console.log('📋 检查必需的环境变量...\n'); const requiredEnvs = [ { key: 'WECHAT_MP_APP_ID', description: 'AppID' }, { key: 'WECHAT_MP_APP_SECRET', description: 'AppSecret' }, { key: 'WECHAT_MP_TOKEN', description: 'Token(用于签名验证)' }, { key: 'WECHAT_MP_ENCODING_AES_KEY', description: 'EncodingAESKey(用于消息加解密)' }, ]; let hasError = false; requiredEnvs.forEach(({ key, description }) => { const value = process.env[key]; if (!value) { console.error(`❌ 缺少环境变量: ${key} (${description})`); hasError = true; } else { const displayValue = value.length > 20 ? `${value.substring(0, 10)}...${value.substring(value.length - 5)}` : value; console.log(`✅ ${key}:`); console.log(` 值: ${displayValue}`); console.log(` 长度: ${value.length}位`); console.log(` 说明: ${description}\n`); } }); if (hasError) { console.error('\n❌ 配置不完整,请检查 backend/.env 文件'); console.error('\n请参考 backend/WECHAT_ENV_CONFIG.md 进行配置'); process.exit(1); } // ==================== 2. 验证Token长度 ==================== console.log('\n📏 验证Token长度...\n'); const token = process.env.WECHAT_MP_TOKEN!; if (token.length < 3 || token.length > 32) { console.error(`❌ Token长度不正确: ${token.length}位(应为3-32位)`); console.error(` 当前Token: ${token}`); hasError = true; } else { console.log(`✅ Token长度正确: ${token.length}位`); } // ==================== 3. 验证EncodingAESKey长度 ==================== console.log('\n🔐 验证EncodingAESKey长度...\n'); const aesKey = process.env.WECHAT_MP_ENCODING_AES_KEY!; if (aesKey.length !== 43) { console.error(`❌ EncodingAESKey长度不正确: ${aesKey.length}位(必须43位)`); console.error(` 当前AESKey: ${aesKey}`); console.error(` 提示: 可以使用以下命令生成43位字符串:`); console.error(` openssl rand -base64 43 | tr -d '/+=' | head -c 43`); hasError = true; } else { console.log(`✅ EncodingAESKey长度正确: 43位`); } // ==================== 4. 测试签名生成 ==================== console.log('\n🔐 测试签名生成...\n'); try { const timestamp = Date.now().toString(); const nonce = Math.random().toString(36).substring(2, 12); const arr = [token, timestamp, nonce].sort(); const str = arr.join(''); const signature = crypto.createHash('sha1').update(str).digest('hex'); console.log(`测试参数:`); console.log(` timestamp: ${timestamp}`); console.log(` nonce: ${nonce}`); console.log(` token: ${token.substring(0, 10)}...`); console.log(`\n排序后拼接: ${str.substring(0, 50)}...`); console.log(`\n生成的签名: ${signature}`); console.log(`\n✅ 签名生成功能正常`); } catch (error: any) { console.error(`❌ 签名生成失败: ${error.message}`); hasError = true; } // ==================== 5. 总结 ==================== console.log('\n' + '='.repeat(60)); if (hasError) { console.error('\n❌ 配置检查失败,请修复以上错误后重试\n'); process.exit(1); } else { console.log('\n✅ 配置检查通过!可以开始配置微信公众平台\n'); console.log('=' .repeat(60)); console.log('\n📋 配置信息(复制以下内容到微信公众平台):\n'); console.log('登录地址:https://mp.weixin.qq.com/'); console.log('配置路径:设置与开发 → 基本配置 → 服务器配置\n'); console.log('配置参数:'); console.log(` URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback`); console.log(` Token: ${token}`); console.log(` EncodingAESKey: ${aesKey}`); console.log(` 消息加解密方式: 安全模式(推荐)`); console.log(` 数据格式: XML`); console.log('\n本地开发环境URL(使用natapp):'); console.log(` URL: https://devlocal.xunzhengyixue.com/api/v1/iit/patient-wechat/callback`); console.log('\n' + '='.repeat(60)); console.log('\n📝 后续步骤:\n'); console.log(' 1. 启动后端服务:npm run dev'); console.log(' 2. 本地开发需要启动natapp内网穿透'); console.log(' 3. 登录微信公众平台,配置服务器地址'); console.log(' 4. 点击"提交"进行URL验证'); console.log(' 5. 验证成功后点击"启用"'); console.log(' 6. 运行测试脚本验证功能:'); console.log(' npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts'); console.log('\n'); }