App 调起支付宝 payOrder 时如何获取用户唯一标识
结论
payOrder 只用于发起 App 支付,无法在支付过程中直接获取当前支付宝登录用户的 auth_code 或用户资料。支付与用户授权是两套独立流程,不能把 auth_V2 的授权功能嵌入 payOrder。
应根据业务目的选择处理方式:
- 如果需要在支付前识别支付宝用户,应单独调用
auth_V2,再由服务端使用auth_code换取用户标识。 - 如果只想确认订单最终由哪个支付宝用户付款,可以在支付完成后,由服务端从支付宝异步通知或交易查询结果中读取付款方标识。
- 订单与 App 账号之间的关系,应通过商户订单号和本地登录账号建立,不建议依赖支付宝用户标识判断订单归属。
为什么 payOrder 拿不到 auth_code
payOrder 调用的是 App 支付接口,负责:
- 唤起支付宝收银台;
- 让用户确认并完成付款;
- 返回支付处理结果。
auth_code 是支付宝会员授权流程中的临时凭证,只有用户明确同意授权后才会生成。支付确认不等于账号授权,因此用户完成付款后,支付宝不会通过 payOrder 返回 auth_code。
客户端收到的同步支付结果主要用于更新交互界面,不应作为最终支付凭据,也不能用来推导用户身份。
方案一:支付前单独完成支付宝授权
如果业务需要确认当前支付宝登录用户的身份,例如绑定支付宝账号或建立会员关系,可以先走一遍独立授权流程。
流程如下:
- 商户服务端生成支付宝授权请求参数;
- App 调用
auth_V2唤起支付宝授权页面; - 用户确认授权;
- App 从授权结果中取得
auth_code; - App 将
auth_code发送给商户服务端; - 服务端调用
alipay.system.oauth.token换取用户标识及令牌; - 完成账号绑定后,再调用
payOrder发起支付。
客户端示意代码:
AuthTask authTask = new AuthTask(activity);
Map<String, String> result = authTask.authV2(authInfo, true);
String resultStatus = result.get("resultStatus");
String resultData = result.get("result");
// 不要仅在客户端完成身份绑定。
// 应解析出 auth_code,并立即提交给商户服务端。
服务端使用 auth_code 换取令牌的示意代码:
AlipaySystemOauthTokenRequest request =
new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(authCode);
AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String accessToken = response.getAccessToken();
String userId = response.getUserId();
// 将支付宝用户标识与当前 App 账号建立绑定关系
} else {
// 记录错误码并按业务规则处理
}
接口最终返回 user_id、open_id 还是其他标识,取决于应用类型、授权范围及支付宝当时的开放平台规则。接入时要以实际接口响应和已经申请的权限为准,不能假设所有应用都会得到相同字段。
方案二:支付成功后识别实际付款方
如果只是想记录”这笔交易由哪个支付宝账号支付”,通常无须提前授权。
可以按以下流程处理:
- 创建商户订单,并生成唯一的
out_trade_no; - 服务端生成 App 支付订单字符串;
- App 调用
payOrder; - 支付宝向商户服务端发送异步通知;
- 服务端验签并核对订单信息;
- 从通知或交易查询结果中读取可用的付款方标识。
客户端调用示例:
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
String resultStatus = result.get("resultStatus");
// 此结果只用于客户端交互提示。
// 最终支付状态应由服务端异步通知或主动查询确认。
服务端收到异步通知后,至少要完成以下校验:
boolean signVerified = AlipaySignature.rsaCheckV1(
requestParams,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (signVerified) {
String outTradeNo = requestParams.get("out_trade_no");
String tradeNo = requestParams.get("trade_no");
String tradeStatus = requestParams.get("trade_status");
String buyerId = requestParams.get("buyer_id");
String buyerOpenId = requestParams.get("buyer_open_id");
// 继续核对 app_id、seller_id、金额和本地订单状态。
// buyer_id、buyer_open_id 是否返回,应以实际接口及开放平台规则为准。
}
如果异步通知没有到达,或者业务需要主动确认,服务端可以调用交易查询接口,再根据查询结果更新订单状态。
推荐的订单关联方式
用户已经登录 App 时,可以在创建订单时直接建立以下关联:
App 用户 ID
↓
商户订单号 out_trade_no
↓
支付宝交易号 trade_no
↓
支付宝付款方标识(如接口实际返回)
本地订单表可以保存:
order_id
app_user_id
out_trade_no
trade_no
buyer_id 或 buyer_open_id
payment_status
paid_at
即使付款人与 App 登录账号不是同一个人,例如订单由亲友代付,订单仍归属于下单账号,同时可以根据接口的实际返回情况记录付款方信息。
注意事项
- 不要尝试通过支付宝客户端环境、设备信息或支付结果字符串反推出当前登录账号。
auth_code有时效性,而且通常只能使用一次,取得后应立即提交给服务端兑换。access_token、应用私钥等敏感信息不能保存在客户端。- 不要仅凭
payOrder返回的resultStatus=9000将订单标记为最终支付成功。 - 服务端必须验证支付宝签名,并核对
app_id、收款方、订单号、金额和交易状态。 - 付款方标识不一定对应 App 当前登录用户,也不能将手机号、邮箱等可变信息作为唯一主键。
- 用户授权必须有明确的业务目的,并遵循最小权限原则。
需要绑定支付宝账号时,应使用独立的 auth_V2 授权流程。如果只需要识别某笔订单的实际付款方,则以服务端收到的异步通知或交易查询结果为准。
备注:内容仅供参考。
