Files
pay/docs/支付宝密钥申请与备案依赖.html
wangjia 6da6964451 初始提交:岩美 pay 收款服务(支付宝当面付 + 多商户多渠道架构)
- Go/Gin/GORM + 纯 Go SQLite(无 cgo)
- Channel 多渠道接口:支付宝当面付(precreate)/电脑网站支付(page.pay) 已实现,微信占位
- 多商户 merchants 表,回调验签+金额核对+幂等+查单兜底
- 收款页/结果页/二维码端点;docs/ 设计文档与部署 Runbook
- 密钥走环境变量/Bitwarden,不入库

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 07:21:48 +08:00

172 lines
14 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>支付宝密钥申请与备案依赖</title>
<style>
:root{--bg:#0d1117;--card:#161b22;--card-2:#1c2330;--border:#283041;--fg:#e6edf3;--fg-soft:#aeb9c7;--muted:#7d8896;--accent:#58a6ff;--green:#3fb950;--orange:#d29922;--red:#f85149;--radius:14px}
*{box-sizing:border-box}
body{margin:0;background:radial-gradient(1200px 600px at 80% -10%,rgba(88,166,255,.08),transparent 60%),var(--bg);color:var(--fg);font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;-webkit-font-smoothing:antialiased}
.wrap{max-width:980px;margin:0 auto;padding:44px 22px 90px}
.eyebrow{color:var(--accent);font-weight:600;letter-spacing:.12em;font-size:12px;text-transform:uppercase}
h1{font-size:28px;margin:10px 0 8px}
.lead{color:var(--fg-soft);margin:0 0 26px}
h2{font-size:19px;margin:38px 0 12px;color:var(--accent);border-bottom:1px solid var(--border);padding-bottom:8px}
h3{font-size:16px;margin:22px 0 8px;color:var(--fg)}
p{color:var(--fg-soft)}
code{background:var(--card-2);border:1px solid var(--border);border-radius:5px;padding:1px 6px;font-size:13px;color:#e6edf3;font-family:"SF Mono",Menlo,Consolas,monospace}
pre{background:var(--card-2);border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-size:13px;line-height:1.55}
pre code{background:none;border:0;padding:0}
a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}
table{width:100%;border-collapse:collapse;margin:14px 0;font-size:14px}
th,td{border:1px solid var(--border);padding:9px 11px;text-align:left;vertical-align:top}
th{background:var(--card-2);color:var(--fg);font-weight:600}
td{color:var(--fg-soft)}
.callout{border-left:3px solid var(--accent);background:var(--card-2);border-radius:0 8px 8px 0;padding:12px 16px;margin:16px 0;color:var(--fg-soft)}
.callout.warn{border-left-color:var(--orange)}
.callout.ok{border-left-color:var(--green)}
.callout.bad{border-left-color:var(--red)}
.step{display:flex;gap:14px;margin:14px 0;background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px}
.step .n{flex:0 0 30px;height:30px;border-radius:50%;background:var(--accent);color:#04122b;font-weight:700;display:flex;align-items:center;justify-content:center}
.step .body{flex:1}
.step .body h3{margin:2px 0 6px}
.pill{font-size:12px;font-weight:600;padding:2px 9px;border-radius:6px}
.pill.sand{background:rgba(63,185,80,.15);color:var(--green)}
.pill.prod{background:rgba(210,153,34,.15);color:var(--orange)}
.yes{color:var(--green);font-weight:600}.no{color:var(--red);font-weight:600}
ul{color:var(--fg-soft)}
svg{display:block;margin:8px auto;max-width:100%}
</style>
</head>
<body>
<div class="wrap">
<div class="eyebrow">pay · Onboarding</div>
<h1>支付宝密钥申请与备案依赖关系</h1>
<p class="lead">沙箱 vs 生产两阶段分别需要什么、密钥怎么拿、备案到底卡在哪一步。配套独立支付服务 <code>pay</code>PC 网页支付 <code>alipay.trade.page.pay</code>)。</p>
<h2>一、两阶段总览</h2>
<table>
<thead><tr><th style="width:24%"></th><th><span class="pill sand">沙箱(现在就能做)</span></th><th><span class="pill prod">生产(收真钱)</span></th></tr></thead>
<tbody>
<tr><td><strong>企业实名</strong></td><td class="no">不需要</td><td class="yes">需要(营业执照/对公/法人)</td></tr>
<tr><td><strong>产品签约</strong></td><td class="no">不需要</td><td class="yes">需签约「电脑网站支付」</td></tr>
<tr><td><strong>域名</strong></td><td class="no">不需要</td><td>签约审核基本要备案域名</td></tr>
<tr><td><strong>ICP 备案</strong></td><td class="no">不需要</td><td>基本绕不开(见第二节)</td></tr>
<tr><td><strong>HTTPS</strong></td><td class="no">不需要(localhost 即可)</td><td class="yes">需要(域名证书)</td></tr>
<tr><td><strong>能验证什么</strong></td><td>下单→跳收银台→扫码付→(查单兜底)全链路</td><td>真实到账 + 异步回调 notify</td></tr>
</tbody>
</table>
<h2>二、不用域名 = 不用备案?</h2>
<p>技术层面:<strong>不绑域名就不触发 ICP 备案</strong>(备案=域名+大陆服务器对外提供服务)。而且有个对支付宝有利的事实:</p>
<div class="callout ok">
<strong>支付宝电脑网站支付的 <code>notify_url</code> / <code>return_url</code> 支付宝不校验是否备案</strong>——只要能 POST 回调到你的地址就行。这点和微信不同(微信 JSAPI/H5 要在后台填「已备案授权域名」)。所以单从回调技术看,甚至能用服务器公网 IP 当 notify_url 把真实支付跑通。
</div>
<p>但「想正经收真钱」时,备案基本还是绕不开,卡在这三处:</p>
<table>
<thead><tr><th style="width:26%">卡点</th><th>说明</th></tr></thead>
<tbody>
<tr><td><strong>商户签约审核</strong></td><td>申请生产「电脑网站支付」要提交<strong>网站地址</strong>,支付宝审核要求网站可正常访问且合规,实践中基本要备案域名(裸 IP 网站过审很难)</td></tr>
<tr><td><strong>HTTPS</strong></td><td>给纯 IP 签受信任 HTTPS 证书极难(Let's Encrypt 不给 IP 发证),无 HTTPS 收款页显示「不安全」</td></tr>
<tr><td><strong>微信支付</strong></td><td>微信必须填备案授权域名,完全绕不开</td></tr>
</tbody>
</table>
<div class="callout bad">
<strong>结论:</strong>沙箱阶段不用域名/备案/实名;真实收款备案是刚需。<strong>但你不必等备案</strong>就能先把支付宝沙箱联调全做完,备案/签约和联调可并行。
</div>
<div class="callout">
完全不备案也想收真钱的旁路:支付宝<strong>「当面付」(扫码)</strong>签约不依赖网站,或用<strong>收款链接 / 第三方托管收银台</strong>——但那不是自研网页收款页这条路。
</div>
<h2>三、沙箱密钥获取(4 步 · 现在就能做)</h2>
<div class="step"><div class="n">1</div><div class="body">
<h3>进沙箱控制台</h3>
<p>支付宝账号登录 → <a href="https://open.alipay.com/develop/sandbox/app">https://open.alipay.com/develop/sandbox/app</a>。页面直接给你 <strong>沙箱 APPID</strong>(形如 <code>9021000xxxxxxxxx</code>)。</p>
</div></div>
<div class="step"><div class="n">2</div><div class="body">
<h3>选「公钥模式」+ 生成密钥</h3>
<p>加签方式选 <strong>公钥模式</strong>(对应代码 <code>LoadAliPayPublicKey</code>)。下载官方<a href="https://opendocs.alipay.com/common/02kipl">密钥生成工具</a>(有 Mac 版)→ 格式 <strong>PKCS8</strong>、长度 <strong>2048</strong> → 生成得到 <strong>应用私钥</strong><strong>应用公钥</strong></p>
</div></div>
<div class="step"><div class="n">3</div><div class="body">
<h3>上传应用公钥 → 换回支付宝公钥</h3>
<p><strong>应用公钥</strong>粘贴到沙箱「公钥模式」处保存,页面会生成一串 <strong>支付宝公钥</strong></p>
<div class="callout warn" style="margin:8px 0 0">别搞混:你<strong>上传</strong>的是「应用公钥」;要<strong>复制回配置</strong>的是支付宝生成的「支付宝公钥」。</div>
</div></div>
<div class="step"><div class="n">4</div><div class="body">
<h3>拿沙箱买家账号</h3>
<p>沙箱页「<strong>沙箱账号</strong>」标签提供买家账号(邮箱)+ 登录密码 + 支付密码(假钱)。扫码付需装<strong>沙箱版支付宝 App</strong>(同页二维码),或用沙箱网页登录买家付款。</p>
</div></div>
<h2>四、生产密钥申请(5 步 · 收真钱)</h2>
<div class="step"><div class="n">1</div><div class="body">
<h3>企业实名</h3>
<p>登录 <a href="https://open.alipay.com">open.alipay.com</a> → 用企业支付宝账号完成企业实名认证(营业执照、法人/对公信息)。个体户用对应类型亦可。</p>
</div></div>
<div class="step"><div class="n">2</div><div class="body">
<h3>创建生产应用</h3>
<p>控制台 → 创建应用 → 选「<strong>网页 &amp; 移动应用</strong>」→ 得到 <strong>正式 APPID</strong></p>
</div></div>
<div class="step"><div class="n">3</div><div class="body">
<h3>签约「电脑网站支付」</h3>
<p>应用里「添加能力/产品签约」→ 签约「<strong>电脑网站支付</strong>」(对应 <code>alipay.trade.page.pay</code>)。需提交企业资质、<strong>网站地址(基本要备案域名)</strong>、经营信息。审核约 13 个工作日。</p>
</div></div>
<div class="step"><div class="n">4</div><div class="body">
<h3>配置生产密钥(同沙箱操作)</h3>
<p>密钥工具生成应用私钥/公钥 → 应用「接口加签方式 → 公钥模式」上传应用公钥 → 复制返回的「支付宝公钥」。</p>
</div></div>
<div class="step"><div class="n">5</div><div class="body">
<h3>切到生产</h3>
<p>把正式 APPID/应用私钥/支付宝公钥写入商户配置,<code>production: true</code>(代码走正式网关),<code>base_url</code> 用正式 HTTPS 备案域名。</p>
</div></div>
<h2>五、三样东西 → 配置对应</h2>
<table>
<thead><tr><th style="width:24%">拿到的</th><th style="width:34%">来源</th><th>填到哪</th></tr></thead>
<tbody>
<tr><td>APPID</td><td>沙箱页面 / 生产应用页直接给</td><td><code>config.yaml → alipay_sandbox.app_id</code>(或 merchants 表)</td></tr>
<tr><td>应用私钥</td><td>你用密钥工具生成,自己保管</td><td>环境变量 <code>ALIPAY_APP_PRIVATE_KEY</code></td></tr>
<tr><td>支付宝公钥</td><td>上传应用公钥后支付宝生成</td><td>环境变量 <code>ALIPAY_PUBLIC_KEY</code></td></tr>
</tbody>
</table>
<pre><code>cd /Users/wangjia/code/pay
export ALIPAY_APP_PRIVATE_KEY="MIIEv...应用私钥..."
export ALIPAY_PUBLIC_KEY="MIIBIj...支付宝公钥..."
# config.yaml 里 alipay_sandbox.enabled=true、填上 app_id
go run .
# 浏览器开 http://localhost:8080 选套餐 → 跳沙箱收银台 → 沙箱买家账号付款</code></pre>
<div class="callout warn">
本机能测「下单 → 跳收银台 → 扫码付成功」整条链路;唯一测不到的是<strong>异步回调 notify</strong>(支付宝回调不到本机)。但服务内置的 <code>query_sync</code> 主动查单兜底会在 30 秒内把订单补成「已支付」,结果页照样变 ✅。要完整验证 notify 需内网穿透或部署到公网服务器。
</div>
<h2>六、推进路线(两线并行,互不等待)</h2>
<svg viewBox="0 0 900 230" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,PingFang SC,sans-serif" font-size="13">
<defs><marker id="ar" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L9,3 L0,6 Z" fill="#58a6ff"/></marker></defs>
<!-- line A -->
<text x="20" y="46" fill="#3fb950" font-weight="600">A · 联调线(现在)</text>
<rect x="20" y="58" width="170" height="44" rx="8" fill="#161b22" stroke="#3fb950"/><text x="105" y="84" fill="#e6edf3" text-anchor="middle">拿沙箱密钥</text>
<line x1="190" y1="80" x2="232" y2="80" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<rect x="234" y="58" width="200" height="44" rx="8" fill="#161b22" stroke="#3fb950"/><text x="334" y="84" fill="#e6edf3" text-anchor="middle">本机跑通支付宝沙箱</text>
<line x1="434" y1="80" x2="476" y2="80" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<rect x="478" y="58" width="200" height="44" rx="8" fill="#161b22" stroke="#283041"/><text x="578" y="84" fill="#aeb9c7" text-anchor="middle">代码就绪 · 等生产</text>
<!-- line B -->
<text x="20" y="150" fill="#d29922" font-weight="600">B · 上线线(并行)</text>
<rect x="20" y="162" width="150" height="44" rx="8" fill="#161b22" stroke="#d29922"/><text x="95" y="188" fill="#e6edf3" text-anchor="middle">域名转入</text>
<line x1="170" y1="184" x2="208" y2="184" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<rect x="210" y="162" width="120" height="44" rx="8" fill="#161b22" stroke="#d29922"/><text x="270" y="188" fill="#e6edf3" text-anchor="middle">ICP 备案</text>
<line x1="330" y1="184" x2="368" y2="184" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<rect x="370" y="162" width="170" height="44" rx="8" fill="#161b22" stroke="#d29922"/><text x="455" y="188" fill="#e6edf3" text-anchor="middle">企业实名+签约</text>
<line x1="540" y1="184" x2="578" y2="184" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<rect x="580" y="162" width="150" height="44" rx="8" fill="#161b22" stroke="#d29922"/><text x="655" y="188" fill="#e6edf3" text-anchor="middle">生产密钥</text>
<!-- merge -->
<line x1="655" y1="102" x2="655" y2="160" stroke="#7d8896" stroke-width="1.5" stroke-dasharray="4 4"/>
<rect x="740" y="110" width="140" height="46" rx="8" fill="#1c2330" stroke="#58a6ff"/><text x="810" y="130" fill="#e6edf3" text-anchor="middle" font-weight="600">换密钥+域名</text><text x="810" y="146" fill="#58a6ff" text-anchor="middle">→ 上线收真钱</text>
<line x1="678" y1="80" x2="738" y2="120" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
<line x1="730" y1="184" x2="800" y2="158" stroke="#58a6ff" stroke-width="2" marker-end="url(#ar)"/>
</svg>
<p>两条线独立推进:A 线现在就能把代码全跑通,B 线(域名/备案/签约)慢慢走;B 线齐了,只需「换生产密钥 + 换备案域名」即可上线,主流程一行不改(<code>Merchant.Production</code> + <code>base_url</code>)。</p>
</div>
</body>
</html>