# 微信公众号与微信支付集成使用指南 本文档说明如何配置和使用系统的微信公众号 OAuth 认证和微信支付功能。 ## 目录 - [概述](#概述) - [前置条件](#前置条件) - [配置步骤](#配置步骤) - [1. 微信公众号配置](#1-微信公众号配置) - [2. 微信支付配置](#2-微信支付配置) - [3. 证书文件配置](#3-证书文件配置) - [环境变量配置](#环境变量配置) - [功能说明](#功能说明) - [微信 OAuth 登录](#微信-oauth-登录) - [微信 JSAPI 支付](#微信-jsapi-支付) - [微信 H5 支付](#微信-h5-支付) - [支付回调处理](#支付回调处理) - [常见问题](#常见问题) --- ## 概述 系统集成了以下微信功能: 1. **微信公众号 OAuth 认证**:个人客户可以通过微信授权码登录/绑定账号 2. **微信 JSAPI 支付**:支持微信内网页支付 3. **微信 H5 支付**:支持微信外浏览器 H5 支付 4. **支付回调处理**:自动验证微信支付签名并处理回调 技术实现使用 [PowerWeChat v3 SDK](https://github.com/ArtisanCloud/PowerWeChat)。 --- ## 前置条件 在开始配置之前,您需要: 1. **微信公众号**(已认证) - 公众号 AppID - 公众号 AppSecret - OAuth 回调域名(需在公众号后台配置) 2. **微信商户号**(已开通) - 商户号 MchID - APIv3 密钥(32位字符串) - APIv2 密钥(可选,部分接口需要) - 商户证书(apiclient_cert.pem) - 商户私钥(apiclient_key.pem) - 证书序列号 3. **服务器环境** - 可访问的 HTTPS 域名(用于接收微信回调) - Redis(用于缓存 AccessToken) --- ## 配置步骤 ### 1. 微信公众号配置 #### 1.1 获取 AppID 和 AppSecret 登录 [微信公众平台](https://mp.weixin.qq.com/),在"开发" → "基本配置"中获取: - AppID(应用ID) - AppSecret(应用密钥) #### 1.2 配置 OAuth 回调域名 在"设置与开发" → "公众号设置" → "功能设置" → "网页授权域名"中配置: ``` your-domain.com ``` **注意**: - 不要带 `http://` 或 `https://` - 不要带端口号 - 需要验证域名所有权(下载验证文件到网站根目录) ### 2. 微信支付配置 #### 2.1 获取商户信息 登录 [微信支付商户平台](https://pay.weixin.qq.com/): 1. **商户号(MchID)**:在"账户中心" → "商户信息"中查看 2. **APIv3 密钥**:在"账户中心" → "API安全" → "设置APIv3密钥"中设置(32位字符串) 3. **APIv2 密钥**:(可选)同上,设置API密钥(32位字符串) #### 2.2 下载商户证书 在"账户中心" → "API安全" → "申请API证书": 1. 下载证书工具 2. 生成证书请求文件 3. 上传请求文件 4. 下载证书文件: - `apiclient_cert.pem`(商户证书) - `apiclient_key.pem`(商户私钥) #### 2.3 获取证书序列号 **方法1:使用 OpenSSL** ```bash openssl x509 -in apiclient_cert.pem -noout -serial | cut -d= -f2 ``` **方法2:从商户平台查看** 在"账户中心" → "API安全" → "API证书"中查看证书序列号。 #### 2.4 配置支付回调 URL 在"产品中心" → "开发配置" → "支付配置"中设置: ``` https://your-domain.com/api/callback/wechat-pay ``` **注意**: - 必须使用 HTTPS - 确保服务器可以接收微信的 POST 请求 ### 3. 证书文件配置 将下载的证书文件放置到服务器: ```bash # 创建证书目录 mkdir -p /app/certs # 复制证书文件 cp apiclient_cert.pem /app/certs/ cp apiclient_key.pem /app/certs/ # 设置文件权限(仅所有者可读写) chmod 600 /app/certs/* ``` **Docker 部署**:在 `docker-compose.yml` 中挂载证书目录: ```yaml services: api: volumes: - ./certs:/app/certs:ro # 只读挂载 ``` --- ## 环境变量配置 在 `.env.local` 或生产环境中设置以下环境变量: ```bash # ===== 微信公众号配置 ===== export JUNHONG_WECHAT_OFFICIAL_ACCOUNT_APP_ID="wxabcdef1234567890" export JUNHONG_WECHAT_OFFICIAL_ACCOUNT_APP_SECRET="your_app_secret_here" export JUNHONG_WECHAT_OFFICIAL_ACCOUNT_TOKEN="" # 可选,服务器配置用 export JUNHONG_WECHAT_OFFICIAL_ACCOUNT_AES_KEY="" # 可选,消息加解密用 export JUNHONG_WECHAT_OFFICIAL_ACCOUNT_OAUTH_REDIRECT_URL="" # 可选,自定义回调URL # ===== 微信支付配置 ===== export JUNHONG_WECHAT_PAYMENT_APP_ID="wxabcdef1234567890" # 与公众号 AppID 相同 export JUNHONG_WECHAT_PAYMENT_MCH_ID="1234567890" export JUNHONG_WECHAT_PAYMENT_API_V3_KEY="your_apiv3_key_32_chars_here" export JUNHONG_WECHAT_PAYMENT_API_V2_KEY="" # 可选,部分接口需要 export JUNHONG_WECHAT_PAYMENT_CERT_PATH="/app/certs/apiclient_cert.pem" export JUNHONG_WECHAT_PAYMENT_KEY_PATH="/app/certs/apiclient_key.pem" export JUNHONG_WECHAT_PAYMENT_SERIAL_NO="1234567890ABCDEF" export JUNHONG_WECHAT_PAYMENT_NOTIFY_URL="https://your-domain.com/api/callback/wechat-pay" export JUNHONG_WECHAT_PAYMENT_HTTP_DEBUG=false export JUNHONG_WECHAT_PAYMENT_TIMEOUT="30s" ``` **配置说明**: | 配置项 | 必填 | 说明 | |--------|------|------| | `OFFICIAL_ACCOUNT_APP_ID` | ✅ | 公众号 AppID | | `OFFICIAL_ACCOUNT_APP_SECRET` | ✅ | 公众号 AppSecret | | `PAYMENT_APP_ID` | ✅ | 支付 AppID(通常与公众号相同) | | `PAYMENT_MCH_ID` | ✅ | 商户号 | | `PAYMENT_API_V3_KEY` | ✅ | APIv3 密钥(32位) | | `PAYMENT_CERT_PATH` | ✅ | 商户证书路径 | | `PAYMENT_KEY_PATH` | ✅ | 商户私钥路径 | | `PAYMENT_SERIAL_NO` | ✅ | 证书序列号 | | `PAYMENT_NOTIFY_URL` | ✅ | 支付回调 URL | | `PAYMENT_TIMEOUT` | ❌ | HTTP 请求超时(默认30s) | | `PAYMENT_HTTP_DEBUG` | ❌ | 开启 HTTP 调试日志 | --- ## 功能说明 ### 微信 OAuth 登录 #### 业务流程 ``` 1. 前端引导用户点击"微信登录" 2. 跳转到微信授权页面(微信SDK处理) 3. 用户同意授权后,微信回调到前端 4. 前端获取授权码(code),调用后端登录接口 5. 后端通过 code 获取用户 OpenID/UnionID 6. 后端创建/查找用户,返回 JWT Token ``` #### API 端点 **POST `/api/c/v1/wechat/auth`** 请求体: ```json { "code": "071abc123456789def" } ``` 响应: ```json { "code": 0, "msg": "登录成功", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "customer_id": 123, "phone": "138****8888", "nickname": "微信用户", "is_new_user": false }, "timestamp": "2025-01-30T12:00:00Z" } ``` #### 前端集成示例 ```javascript // 1. 构造微信授权 URL(前端处理) const redirectUri = encodeURIComponent('https://your-domain.com/wechat-callback'); const appId = 'wxabcdef1234567890'; const scope = 'snsapi_userinfo'; // 或 snsapi_base(静默授权) const state = 'STATE'; // 自定义参数 const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`; // 跳转到微信授权页面 window.location.href = authUrl; // 2. 在回调页面获取 code 并调用后端 const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); fetch('https://api.your-domain.com/api/c/v1/wechat/auth', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code }) }) .then(res => res.json()) .then(data => { if (data.code === 0) { localStorage.setItem('token', data.data.token); // 跳转到主页 } }); ``` ### 微信 JSAPI 支付 #### 业务流程 ``` 1. 前端调用后端创建支付订单 2. 后端调用微信支付接口,获取 prepay_id 和支付配置 3. 前端调用微信 JSAPI 唤起支付 4. 用户完成支付后,微信回调后端通知接口 5. 后端验证签名并处理订单状态 ``` #### API 端点 **POST `/api/h5/orders/:id/wechat-pay/jsapi`** 请求体: ```json { "open_id": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M" } ``` 响应: ```json { "code": 0, "msg": "支付订单创建成功", "data": { "prepay_id": "wx30123456789012345678901234567890", "pay_config": { "appId": "wxabcdef1234567890", "timeStamp": "1706606400", "nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS", "package": "prepay_id=wx30123456789012345678901234567890", "signType": "RSA", "paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd..." } }, "timestamp": "2025-01-30T12:00:00Z" } ``` #### 前端集成示例(微信内网页) ```javascript // 1. 调用后端创建支付订单 const response = await fetch(`/api/h5/orders/${orderId}/wechat-pay/jsapi`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ open_id: 'o6_bmjrPTlm6_2sgVt7hMZOPfL2M' }) }); const result = await response.json(); // 2. 调用微信 JSAPI 唤起支付 if (result.code === 0) { const payConfig = result.data.pay_config; wx.chooseWXPay({ ...payConfig, success: function(res) { // 支付成功,跳转到订单详情页 window.location.href = `/orders/${orderId}`; }, fail: function(res) { // 支付失败 alert('支付失败:' + res.err_msg); } }); } ``` ### 微信 H5 支付 #### 业务流程 ``` 1. 前端调用后端创建 H5 支付订单 2. 后端调用微信支付接口,获取 H5 支付 URL 3. 前端跳转到 H5 支付 URL 4. 用户完成支付后,微信回调后端通知接口 5. 后端验证签名并处理订单状态 ``` #### API 端点 **POST `/api/h5/orders/:id/wechat-pay/h5`** 请求体: ```json { "scene_info": { "payer_client_ip": "123.12.12.123", "h5_type": "Wap" } } ``` 响应: ```json { "code": 0, "msg": "H5 支付订单创建成功", "data": { "h5_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx..." }, "timestamp": "2025-01-30T12:00:00Z" } ``` #### 前端集成示例(浏览器) ```javascript // 1. 调用后端创建 H5 支付订单 const response = await fetch(`/api/h5/orders/${orderId}/wechat-pay/h5`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ scene_info: { payer_client_ip: '123.12.12.123', h5_type: 'Wap' } }) }); const result = await response.json(); // 2. 跳转到微信 H5 支付页面 if (result.code === 0) { const returnUrl = encodeURIComponent(`https://your-domain.com/orders/${orderId}`); window.location.href = `${result.data.h5_url}&redirect_url=${returnUrl}`; } ``` ### 支付回调处理 #### 回调端点 **POST `/api/callback/wechat-pay`** 该端点接收微信支付的异步通知。系统会自动: 1. 验证微信签名(使用商户证书) 2. 解密通知数据 3. 更新订单状态 4. 处理业务逻辑(分佣、钱包充值等) 5. 返回成功响应给微信 #### 回调处理流程 ``` 1. 微信发送 POST 请求到回调 URL 2. 系统验证请求签名(PowerWeChat 自动处理) 3. 解析支付结果(交易状态、金额等) 4. 更新订单状态为"已支付" 5. 触发异步任务(分佣计算、套餐分配等) 6. 返回 200 OK 给微信(表示接收成功) ``` **注意**: - 回调接口必须在 **10秒内** 返回响应,否则微信会重试 - 系统已实现幂等性处理,重复通知不会重复处理 - 如果处理失败,微信会重试多次(最多3次) --- ## 常见问题 ### 1. 配置验证失败,服务启动失败 **错误日志**: ``` FATAL: 微信配置不完整或无效 ``` **解决方法**: - 检查所有必填环境变量是否设置 - 确认证书文件路径正确且文件存在 - 验证 APIv3 密钥是否为 32 位字符串 ### 2. OAuth 授权失败,返回 1044 错误 **错误消息**: ```json { "code": 1044, "msg": "微信 OAuth 授权失败" } ``` **可能原因**: - 授权码(code)已过期(5分钟有效期) - 授权码已被使用过(一次性有效) - AppID 或 AppSecret 配置错误 - 回调域名未在公众号后台配置 **解决方法**: - 重新发起授权流程获取新 code - 检查公众号配置是否正确 - 查看 `logs/app.log` 获取详细错误信息 ### 3. 支付订单创建失败,返回 1046 错误 **错误消息**: ```json { "code": 1046, "msg": "微信支付失败" } ``` **可能原因**: - 商户号配置错误 - 证书文件无效或过期 - APIv3 密钥错误 - 订单金额为0或负数 **解决方法**: - 验证商户号和密钥是否正确 - 检查证书文件是否可读(权限问题) - 确认证书序列号是否匹配 - 查看 `logs/app.log` 获取详细错误信息 ### 4. 支付回调签名验证失败 **错误日志**: ``` ERROR: 支付回调签名验证失败 ``` **可能原因**: - 证书配置错误 - 证书序列号不匹配 - 证书已过期 **解决方法**: - 重新下载最新的商户证书 - 更新证书序列号配置 - 确保证书文件路径正确 ### 5. 如何测试微信支付? **开发环境测试**: 1. 使用微信测试号(公众号测试账号) 2. 使用真实商户号的沙箱环境(需申请) 3. 使用 0.01 元测试订单(生产环境) **注意**: - 测试订单需要真实支付 - 可以通过退款功能退回测试金额 - 建议使用沙箱环境进行测试 ### 6. Redis 连接失败,影响微信功能吗? **是的**,微信功能依赖 Redis 缓存 AccessToken。 **解决方法**: - 确保 Redis 服务正常运行 - 检查 Redis 连接配置(地址、端口、密码) - 查看 `logs/app.log` 获取 Redis 连接错误 ### 7. 如何调试微信支付问题? **启用 HTTP 调试日志**: ```bash export JUNHONG_WECHAT_PAYMENT_HTTP_DEBUG=true ``` 重启服务后,所有微信 API 请求和响应将记录到 `logs/app.log`。 **查看日志**: ```bash tail -f logs/app.log | grep -i wechat ``` --- ## 相关文档 - [微信公众号官方文档](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html) - [微信支付官方文档](https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml) - [PowerWeChat SDK 文档](https://github.com/ArtisanCloud/PowerWeChat) - [API 文档](./API文档.md) - [环境变量配置](../environment-variables.md)