支付宝支付如何使用公钥证书模式并支持提现
结论
支付宝支持公钥证书模式,支付接口也可以通过这种模式调用。如果提现或转账接口明确要求使用公钥证书模式,建议将同一应用的支付宝客户端整体切换到证书模式,让支付、查询、退款、转账和异步通知验签共用一套证书配置。
公钥证书模式并非另一套支付接口。alipay.trade.page.pay、alipay.trade.app.pay、alipay.trade.wap.pay 等接口通常无须更换,只需调整签名和验签配置。
还要注意,“提现”可能指商家转账、余额转出或其他资金产品。具体接口名称和准入条件,应以该应用在支付宝开放平台已签约的产品为准,不能只根据“提现”这个名称判断接口。
为什么支付能用公钥模式,提现却要求证书模式
支付宝开放平台常见的接口加签方式有两种:
- 普通公钥模式:使用应用私钥签名,通过已配置的支付宝公钥验签。
- 公钥证书模式:除应用私钥外,还需要应用公钥证书、支付宝公钥证书和支付宝根证书。
部分资金类接口要求使用公钥证书模式,以便通过证书序列号识别签名主体,同时支持证书链校验和证书更新。因此,支付接口能够通过普通公钥模式调用,不代表资金类接口也支持相同的模式。
切换后,SDK通常会自动在请求中携带 app_cert_sn 和 alipay_root_cert_sn,业务代码仍然调用原来的支付或资金接口。
需要准备的证书
进入支付宝开放平台中的对应应用,找到“接口加签方式”或相关开发设置,选择公钥证书模式。按照平台指引生成并上传应用公钥证书,然后下载以下文件:
- 应用公钥证书,例如
appCertPublicKey_应用APPID.crt - 支付宝公钥证书,例如
alipayCertPublicKey_RSA2.crt - 支付宝根证书,例如
alipayRootCert.crt
还需要保留生成应用公钥证书时所对应的应用私钥。私钥应存放在服务端,不能上传到代码仓库,也不能放进前端、客户端安装包或公开配置文件。
这些证书必须属于当前调用所使用的 app_id,沙箱应用和正式应用的证书不能混用。
Java SDK 配置示例
支付宝 Java SDK的不同版本,在配置类和字段名称上可能略有区别。较新的版本通常使用 AlipayConfig:
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
AlipayConfig config = new AlipayConfig();
config.setServerUrl("https://openapi.alipay.com/gateway.do");
config.setAppId("YOUR_APP_ID");
config.setPrivateKey("YOUR_APP_PRIVATE_KEY");
config.setFormat("json");
config.setCharset("UTF-8");
config.setSignType("RSA2");
config.setAppCertPath("/secure/alipay/appCertPublicKey.crt");
config.setAlipayPublicCertPath("/secure/alipay/alipayCertPublicKey_RSA2.crt");
config.setRootCertPath("/secure/alipay/alipayRootCert.crt");
AlipayClient alipayClient = new DefaultAlipayClient(config);
部分旧版 SDK使用 CertAlipayRequest:
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
CertAlipayRequest config = new CertAlipayRequest();
config.setServerUrl("https://openapi.alipay.com/gateway.do");
config.setAppId("YOUR_APP_ID");
config.setPrivateKey("YOUR_APP_PRIVATE_KEY");
config.setFormat("json");
config.setCharset("UTF-8");
config.setSignType("RSA2");
config.setCertPath("/secure/alipay/appCertPublicKey.crt");
config.setAlipayPublicCertPath("/secure/alipay/alipayCertPublicKey_RSA2.crt");
config.setRootCertPath("/secure/alipay/alipayRootCert.crt");
AlipayClient alipayClient = new DefaultAlipayClient(config);
请根据项目实际使用的支付宝 SDK版本选择一种写法,不要混用两套配置。
使用证书客户端调用支付接口
初始化客户端后,支付接口的调用方式基本不变:
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("https://example.com/alipay/return");
request.setNotifyUrl("https://example.com/alipay/notify");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "99.00",
"subject": "订单支付",
"product_code": "FAST_INSTANT_TRADE_PAY"
}
""");
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
String paymentForm = response.getBody();
// 将 paymentForm 返回给浏览器或写入 HTTP 响应
} else {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
这里调用的仍是 alipay.trade.page.pay。证书模式客户端会处理证书序列号和请求签名,无须在业务参数中手工拼接。
接入提现或转账接口
接入前,先在支付宝开放平台确认以下信息:
- 应用是否已签约对应的资金产品;
- 实际开放的 API 名称;
- 收款方身份类型和必填字段;
- 是否需要资金授权、审核、额度或其他准入条件;
- 当前应用是否被要求使用公钥证书模式。
如果实际使用商家转账类接口,应复用前面创建的 AlipayClient,不要为支付和转账分别维护普通公钥客户端和证书客户端。
下面只展示调用结构。具体请求类和业务字段,必须以已签约产品对应的接口文档为准:
AlipayFundTransUniTransferRequest request =
new AlipayFundTransUniTransferRequest();
request.setBizContent("""
{
"out_biz_no": "TRANSFER_202609090001",
"trans_amount": "10.00",
"product_code": "TRANS_ACCOUNT_NO_PWD",
"biz_scene": "DIRECT_TRANSFER",
"order_title": "用户提现",
"payee_info": {
"identity": "receiver@example.com",
"identity_type": "ALIPAY_LOGON_ID"
}
}
""");
AlipayFundTransUniTransferResponse response =
alipayClient.certificateExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
alipay.fund.trans.uni.transfer 是否适用于当前业务、是否仍向该应用开放,以及应该使用 execute 还是 certificateExecute,都取决于当前 SDK版本和支付宝为该应用开通的产品。请以开放平台控制台生成的接口示例和当前 SDK文档为准。
异步通知也要改为证书验签
切换到证书模式后,支付和资金接口的异步通知也应通过支付宝公钥证书验签。Java SDK中的常见写法如下:
import com.alipay.api.internal.util.AlipaySignature;
boolean verified = AlipaySignature.rsaCertCheckV1(
requestParams,
"/secure/alipay/alipayCertPublicKey_RSA2.crt",
"UTF-8",
"RSA2"
);
if (!verified) {
throw new SecurityException("支付宝异步通知验签失败");
}
requestParams 必须使用支付宝通知中的原始参数构造。验签前不要对参数值进行 URL 解码、JSON重组、格式化或字段删改,否则可能导致验签失败。
验签通过后,还需要核对:
app_id是否属于当前应用;out_trade_no或业务单号是否存在;- 金额和币种是否与本地订单一致;
- 交易状态是否符合处理条件;
- 该通知是否已经处理,避免重复入账或重复发货。
切换时的注意事项
证书模式通常属于应用级配置。启用后,不要默认原有普通公钥模式可以长期与证书模式并行使用。支付请求、查询、退款、关闭订单、转账和异步通知验签都要一并检查。
上线前建议完成以下验证:
- 使用正式应用对应的三份证书和私钥;
- 确认私钥与应用公钥证书匹配;
- 检查部署环境能否读取证书路径;
- 确认证书文件内容没有被当作普通支付宝公钥使用;
- 验证支付下单、同步跳转和异步通知;
- 验证查询、退款和资金类接口;
- 对相同业务单号实施幂等控制;
- 记录支付宝返回的
code、sub_code、msg和sub_msg,但不要记录私钥或完整的敏感信息; - 建立证书更新机制,避免证书更换后,请求或通知突然无法通过验签。
较稳妥的做法是将整个应用的支付宝 SDK初始化和验签逻辑统一迁移到公钥证书模式,再通过同一个证书客户端调用支付接口和已获准使用的资金接口。
备注:内容仅供参考。
