支付宝沙盒支付提示ACCESS_FORBIDDEN怎么解决?
结论
ACCESS_FORBIDDEN 表示当前请求无权访问对应的支付宝应用或支付能力。
遇到 APPID 2021000121647104 时,先确认它是不是当前支付宝开放平台账号下的沙盒应用 APPID。不要直接使用示例、教程或他人的 APPID。沙盒请求使用的 APPID、应用私钥、支付宝公钥、网关地址和沙盒买家账号,必须来自同一套沙盒环境。
如果这些配置完全匹配但错误仍然存在,请检查该沙盒应用是否已开通当前调用的支付产品,以及所用接口是否与应用类型相符。
常见原因
1. 使用了不属于自己的 APPID
APPID 不是公共测试参数。即使某个 APPID 出现在示例代码中,也不能直接拿来发起自己的支付请求。
应用私钥只能为配套的 APPID 生成有效签名。即使请求通过了部分参数校验,如果应用没有相应权限,收银台仍可能显示:
订单信息有错误,建议联系卖家。
错误码:ACCESS_FORBIDDEN
2. 正式环境与沙盒环境混用
以下配置都必须来自沙盒环境:
- 沙盒应用 APPID
- 应用私钥
- 沙盒应用配置的支付宝公钥
- 沙盒网关
- 沙盒买家账号
- 沙盒支付接口权限
例如,用沙盒 APPID 请求正式网关,或者用正式应用的密钥为沙盒请求签名,都属于环境混用。
3. 公钥或私钥配置错误
下面几项很容易混淆:
- 应用私钥:由商户保存,用于为请求签名
- 应用公钥:上传到支付宝开放平台
- 支付宝公钥:从开放平台的应用配置中获取,用于验证支付宝返回的数据
- 支付宝公钥证书:用于证书模式,不能直接作为普通公钥配置
普通公钥模式与证书模式的客户端初始化方式不同,不能混用。
4. 应用未获得目标接口权限
调用 alipay.trade.app.pay 时,应用需要开通对应的 APP 支付能力。调用网页支付、手机网站支付或当面付接口,也需要开通相应的产品权限。
如果应用类型、已开通产品与实际调用的接口不一致,也可能出现权限禁止类错误。
解决步骤
第一步:获取自己的沙盒 APPID
登录支付宝开放平台,进入沙盒应用页面,复制当前账号下显示的 APPID。
将代码中的:
2021000121647104
替换成你自己的沙盒应用 APPID。除非开放平台明确显示该 APPID 属于你的应用,否则不要使用它。
第二步:重新核对密钥
确认请求使用的是该沙盒应用对应的应用私钥,并把与之匹配的应用公钥配置到同一个应用中。
如果重新生成过密钥,旧私钥将无法与新上传的应用公钥配套使用。此时需要同步更新项目配置并重新启动应用,避免程序继续读取缓存或旧配置。
第三步:确认使用沙盒网关
普通公钥模式的 Java SDK 初始化示例如下:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
"你的沙盒APPID",
"你的应用私钥",
"json",
"UTF-8",
"你的支付宝公钥",
"RSA2"
);
沙盒网关地址可能会随开放平台调整,请以当前沙盒控制台或官方 SDK 文档显示的地址为准,不要直接复制过期教程中的地址。
第四步:检查支付接口
APP 支付应调用:
alipay.trade.app.pay
Java 示例:
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject("测试商品");
model.setOutTradeNo("TEST_" + System.currentTimeMillis());
model.setTotalAmount("0.01");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (response.isSuccess()) {
String orderString = response.getBody();
System.out.println(orderString);
} else {
System.out.println(response.getCode());
System.out.println(response.getSubCode());
System.out.println(response.getSubMsg());
}
生成 orderString 后,应将它原样交给支付宝客户端 SDK,不要自行进行二次 URL 编码,也不要拆分或重新拼接。
第五步:查看服务端的完整错误信息
不要只看支付宝收银台显示的 ACCESS_FORBIDDEN。服务端 SDK 返回的信息通常更有助于定位问题,建议记录:
System.out.println("code=" + response.getCode());
System.out.println("msg=" + response.getMsg());
System.out.println("subCode=" + response.getSubCode());
System.out.println("subMsg=" + response.getSubMsg());
System.out.println("body=" + response.getBody());
重点检查 subCode 和 subMsg,用它们判断具体属于哪种情况:
- 应用无接口权限
- APPID 不匹配
- 签名配置错误
- 产品未开通
- 接口与应用类型不匹配
不要在日志中输出完整的应用私钥,也不要长期保存含有敏感信息的完整支付参数。
第六步:使用沙盒账号测试
沙盒订单需要使用开放平台提供的沙盒买家账号完成支付,不要将真实支付宝账号用于沙盒支付流程。
如果应用服务端生成的是沙盒订单,客户端也应按照官方测试说明使用对应的沙盒测试环境。
配置检查清单
建议按以下顺序逐项排查:
- APPID 是否来自自己的沙盒应用。
- 应用私钥是否与该 APPID 当前配置的应用公钥配套。
- 配置的是否为支付宝公钥,而不是应用公钥。
sign_type是否与密钥类型一致,通常为RSA2。- 网关是否为当前官方提供的沙盒网关。
- 调用
alipay.trade.app.pay时,应用是否已具备 APP 支付能力。 product_code是否为QUICK_MSECURITY_PAY。- 是否使用沙盒买家账号进行支付。
- 是否将服务端生成的订单字符串原样传给客户端 SDK。
- 是否查看了服务端返回的
subCode和subMsg。
注意事项
ACCESS_FORBIDDEN 通常不是订单金额、商品名称或商户订单号格式错误造成的。修改 subject、total_amount,或者反复创建新订单,一般无法解决权限问题。
也不要通过随机更换 APPID 来碰运气。APPID 与密钥、应用权限和运行环境相互绑定,必须成套配置。
如果已经确认 APPID、密钥、网关和接口权限都正确,但错误依然存在,请携带服务端返回的 code、subCode、subMsg、请求接口名称和支付宝返回的请求标识,前往支付宝开放平台技术支持渠道进一步查询。不要提交应用私钥或其他完整密钥材料。
备注:内容仅供参考。
