PAYATHON 2026

支付宝 APP 支付中两类支付宝密钥的区别及公钥选择

支付小周

明确结论

这两处密钥分属不同的接口体系,不能因为名称相同就混用:

  • “应用设置 → 开发设置 → 接口加签方式”用于支付宝开放平台 OpenAPI,例如 alipay.trade.app.pay。
  • “mapi 网关产品密钥”用于旧版 MAPI 接口,也就是请求地址、参数规范和签名规则均属于 mapi 网关的产品。
  • 通过 alipay.trade.app.pay 拉起支付宝 APP 支付时,服务端应使用应用私钥签名;验签时则使用”接口加签方式”对应的支付宝公钥。
  • 拉起支付时,通常不需要把支付宝公钥作为业务参数传给支付宝客户端。商户需要用它验证支付宝的响应和异步通知。
  • MAPI 页面中的支付宝公钥只适用于对应的 MAPI 请求链路,不能用来验证 OpenAPI 的支付通知。

判断该用哪套密钥,要看实际调用的接口和网关,而不是看它们是否都用于 APP 支付。

两套密钥分别做什么

接口加签方式中的密钥

这套配置以开放平台应用为边界,通常包括:

  • 应用私钥:由商户保存,用于对请求参数签名。
  • 应用公钥:由商户上传给支付宝,支付宝用它验证商户请求。
  • 支付宝公钥:由支付宝提供,商户用它验证支付宝的返回结果、异步通知等数据。

调用以下接口时,应使用这套配置:

alipay.trade.app.pay
alipay.trade.query
alipay.trade.refund
alipay.trade.close

常见网关地址为:

https://openapi.alipay.com/gateway.do

mapi 网关产品密钥

MAPI 是另一套接口体系,通常与历史签约产品、旧版网关及其账号标识绑定,有独立的密钥配置、请求参数和验签规则。

一般可以通过以下特征识别:

  • 请求发送到 MAPI 网关;
  • 参数中可能有 service、partner、seller_id 等旧接口字段;
  • 接口文档明确要求使用 MAPI 产品密钥;
  • 签名算法和字符编码需遵循相应的 MAPI 接口文档。

MAPI 页面中的支付宝公钥用于验证该产品链路中由支付宝签名的数据。即使它也是 RSA 公钥,也不代表它可以和开放平台应用下的支付宝公钥互换。

APP 支付到底使用哪个公钥

如果服务端调用的是:

alipay.trade.app.pay

各环节应使用以下密钥:

操作使用的密钥
服务端生成 APP 支付订单并签名应用私钥
支付宝验证商户提交的订单已上传的应用公钥
商户验证支付宝异步通知接口加签方式中的支付宝公钥
商户验证支付宝同步返回数据接口加签方式中的支付宝公钥
APP 客户端调用支付 SDK使用服务端返回的已签名订单字符串,不传支付宝公钥

因此,对于”拉起支付宝 APP 付款时应该传哪个支付宝公钥”这个问题,准确答案是:通常一个都不传。

客户端从商户服务端取得签名后的订单字符串,再交给支付宝客户端 SDK。应用私钥也不能放在 Android 或 iOS 客户端中,否则可能被反编译和提取,进而被用于伪造订单。

正确的调用流程

1. 确认正在使用的接口体系

先检查服务端实际调用的接口名称和网关地址。

如果代码使用:

alipay.trade.app.pay
https://openapi.alipay.com/gateway.do

就应使用”接口加签方式”中的整套密钥。

只有接口文档明确指定 MAPI 网关时,才使用”mapi 网关产品密钥”。

2. 在服务端配置开放平台密钥

以普通公钥模式为例,服务端需要保存:

APP_ID
APP_PRIVATE_KEY
ALIPAY_PUBLIC_KEY

其中:

  • APP_PRIVATE_KEY 用于给请求签名;
  • ALIPAY_PUBLIC_KEY 用于验证支付宝签名;
  • 两者用途相反,不能互换。

应用公钥也不能误当作支付宝公钥。前者属于商户密钥对,后者属于支付宝密钥对。

3. 服务端生成签名订单

下面以 Java SDK 的普通公钥模式为例。SDK 版本不同,类名和方法可能有所变化,请以当前使用的支付宝官方 SDK 文档为准。

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipay.com/gateway.do",
    APP_ID,
    APP_PRIVATE_KEY,
    "json",
    "UTF-8",
    ALIPAY_PUBLIC_KEY,
    "RSA2"
);

AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/alipay/notify");

AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setSubject("订单支付");
model.setTotalAmount("99.00");
model.setProductCode("QUICK_MSECURITY_PAY");

request.setBizModel(model);

AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderString = response.getBody();

这里的 orderString 已经包含服务端生成的签名。客户端直接将它交给支付宝支付 SDK 即可,无需再次签名,也不用追加支付宝公钥。

4. 客户端拉起支付宝

Android 端通常按以下方式调用:

PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderString, true);

orderString 必须由商户服务端生成。不要在客户端使用应用私钥拼装或签名订单。

客户端返回的结果只能用于界面展示。最终支付状态应以服务端收到且验签成功的异步通知为准,也可以由服务端主动调用订单查询接口确认。

5. 服务端验证异步通知

在普通公钥模式下,可以使用开放平台配置中的支付宝公钥验签:

boolean verified = AlipaySignature.rsaCheckV1(
    requestParams,
    ALIPAY_PUBLIC_KEY,
    "UTF-8",
    "RSA2"
);

验签通过后,还要检查以下业务字段:

app_id
out_trade_no
total_amount
seller_id
trade_status

通知处理也要具备幂等性,避免同一通知被重复执行。

容易混淆的三个概念

应用公钥

应用公钥由商户生成并上传给支付宝,与商户保存的应用私钥成对。支付宝用它验证商户请求。

支付宝公钥

支付宝公钥由支付宝提供,与支付宝持有的私钥成对。商户用它验证支付宝签名。

MAPI 中的支付宝公钥

这个公钥只用于对应的 MAPI 产品和接口链路。不能因为名称同为”支付宝公钥”,就把它复制到 OpenAPI SDK 的配置中。

即使两个页面显示的公钥内容碰巧一致,也应按照接口归属分别配置,不能假设它们永远相同。后续更换密钥或迁移产品后,这种假设可能导致验签失败。

如何快速排查选错密钥

如果遇到 isv.invalid-signature、验签失败或通知无法通过校验,可以按以下顺序检查:

  1. 实际调用的是 OpenAPI 还是 MAPI。
  2. SDK 中配置的是支付宝公钥,还是误用了应用公钥。
  3. 请求签名是否使用了应用私钥。
  4. 签名算法是否一致,例如是否统一使用 RSA2。
  5. 公钥是否属于当前 app_id 和当前运行环境。
  6. 是否混用了沙箱密钥和正式环境密钥。
  7. 公钥内容是否完整,头尾标记或换行是否被错误处理。
  8. 验签时是否使用了支付宝发送的原始通知参数,是否在验签前修改、解码或重新拼装过字段。

证书模式需要单独处理

如果”接口加签方式”选择的是证书模式,就不能继续按照普通公钥模式只配置一个 ALIPAY_PUBLIC_KEY。通常需要配置:

  • 应用公钥证书;
  • 支付宝公钥证书;
  • 支付宝根证书。

证书模式应使用 SDK 对应的证书初始化和验签方法,不能从证书文件中截取一段公钥,再把它当作普通支付宝公钥使用。

选择密钥时,应以调用的网关和接口为准。对于当前的 OpenAPI APP 支付,服务端用应用私钥签名,并使用开放平台接口加签配置对应的支付宝公钥或证书验签。客户端不能携带任何私钥,通常也不需要传入支付宝公钥。

备注:内容仅供参考。