uniapp/手机APP使用支付宝支付(服务端)

uniapp/手机APP使用支付宝支付(服务端)_第1张图片

博主介绍:✌全网粉丝4W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战、定制、远程,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌

博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端分离项目,可以在左边的分类专栏找到更多项目。《Uniapp项目案例》有几个有uniapp教程,企业实战开发。《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦

开源项目免费哦:点击这里克隆或者下载  ,已经发布Vue3版  

文末获取联系精彩专栏推荐订阅 不然下次找不到哟

 Java项目案例《100套》

https://blog.csdn.net/qq_57756904/category_12173599.html

 uniapp小程序《100套》

https://blog.csdn.net/qq_57756904/category_12199600.html

目录

一、前言

二、获取APPID

三、设置应用

四、集成和开发

五、调用接口

六、调试应用

七、生产联调


一、前言

最近做了下接入支付宝支付,客户端使用uniapp,不过都是基于支付宝App支付那套规范约定去处理。之前想着接入其他第三方支付来着,但是不是很靠谱,而且可能存在一些其他隐患,还是直接些接入正规的支付宝·支付。下面就对接入做一些讲解:

二、获取APPID

要在您的应用中接入支付宝App支付能力,需要通过创建应用的方式接入蚂蚁相关接口并进行开发,基于对行业及业务场景痛点的理解,创造能够满足市场需要的解决方案,以应用的形式服务用户。

若还未成为开放平台的入驻服务商或者商户, 请完成。入驻完成后,您需要去蚂蚁金服开放平台(open.alipay.com),在开发者中心中创建您的应用,会为您生成应用唯一标识(APPID),并且可以申请开通开放产品使用权限,通过APPID您的应用才能调用开放产品的接口能力。需要详细了解开放平台创建应用步骤请参考《开放平台应用创建指南》。

在创建应用后即生成应用的标识APPID,使用支付宝账号登录开放平台后,在“我的应用”中查看APPID。

三、设置应用

应用创建完成后,需要给应用添加App支付功能,这样就可以在你的应用里使用App支付能力。此时该应用为开发中状态,只能在沙箱环境下进行调试。应用开发完成后,请开发者自行进行验收和安全性检查(安全性检查可参考《开放平台第三方应用安全开发指南》),验收检查完成后可申请上线。应用申请上线后,会同时申请此列表的功能,接口即生效,这个状态下的应用能够调用生产环境的接口。

签约

在使用这些能力的时候,需要在开放平台里进行签约,这时候约定的合同就生效了。也可以代替商户签约。

配置密钥

为了保证交易双方(商户和支付宝)的身份和数据安全,开发者在调用接口前,需要配置双方密钥,对交易数据进行双方校验。

1、了解下支付宝密钥处理体系:

uniapp/手机APP使用支付宝支付(服务端)_第2张图片

2、密钥包含:

应用公钥:由商户自己生成的RSA公钥(与应用私钥必须匹配),商户需上传应用公钥到支付宝开放平台,以便支付宝使用该公钥验证该交易是否是商户发起的。

应用私钥:由商户自己生成的RSA私钥(与应用公钥必须匹配),商户开发者使用应用私钥对请求字符串进行加签。

支付宝公钥:支付宝的RSA公钥,商户使用该公钥验证该结果是否是支付宝返回的。

生成密钥后在开放平台开发者中心进行密钥配置,配置完成后可以获取支付宝公钥。具体方法流程请参见上传应用公钥并获取支付宝公钥。

3、配置生成的密钥等应用信息。配置的详细步骤请参考《配置应用环境》。

注:签名验签常见问题排查

支付宝开放平台SDK封装了签名和验签过程,只需配置账号及密钥参数,强烈建议使用。更多签名问题的自助排查流程,可以参考支付宝验签专区的未使用开放平台SDK的自助排查流程。关于同步通知和异步通知的验签规则,可参考验签教程。

更多关于签名教程和签名工具下载等问题,请参见签名专区。

四、集成和开发

服务端SDK需要商户集成在自己的服务端系统中,用于协助解析并验证客户端同步返回的支付结果和异步通知。

maven引入如下依赖

            com.alipay.sdk        alipay-sdk-java        4.8.10.ALL    

五、调用接口

为了避免在线上生产环境联调过程中遇到问题,建议在沙箱环境中联调通过后再在线上生产环境进行联调,具体操作步骤见沙箱联调指南。如果需要在线上调用接口,需要参考下面第六步:应用上线后再进行接口调用,不然会报出“无权限错误”。

系统交互流程:

uniapp/手机APP使用支付宝支付(服务端)_第3张图片

图中虚线标识商户链路,实线标识支付宝链路。

第4步:调用支付接口:此消息就是本接口所描述的支付宝客户端SDK提供的支付对象PayTask,将商户签名后的订单信息传进payv2方法唤起支付宝收银台,交易数据格式具体参见请求参数说明。

第5步:支付请求:支付宝客户端SDK将会按照商户客户端提供的请求参数发送支付请求。

第8步:接口返回支付结果:商户客户端在第4步中调用的支付接口,会返回最终的支付结果(即同步通知),参见客户端同步返回。

第13步:用户在支付宝APP或H5收银台完成支付后,会根据商户在手机网站支付API中传入的前台回跳地址return_url自动跳转回商户页面,同时在URL请求中附带上支付结果参数。同时,支付宝还会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统,详情见支付结果异步通知。

除了正向支付流程外,支付宝也提供交易查询、关闭、退款、退款查询以及对账等配套API。

特别注意:

构造交易数据并签名必须在商户服务端完成,商户的应用私钥绝对不能保存在商户APP客户端中,也不能从服务端下发。

同步返回的数据,只是一个简单的结果通知,商户确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断。

商户系统接收到通知以后,必须通过验签(验证通知中的sign参数)来确保支付通知是由支付宝发送的。建议使用支付宝提供的SDK来完成,详细验签规则参考异步通知验签。

使用SDK快速接入

App支付API必须通过支付宝提供的移动端SDK来调用。

交易操作

以下大致记录针对alipay.trade.app.pay接口的相关代码:

1.APP客户端调用应用服务端,应用服务端通过alipay.trade.app.pay接口传入订单参数,将alipay.trade.app.pay接口返回的AlipayTradeAppPayResponse返回给APP客户端,由APP唤起支付宝客户端。


 
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
import com.alibaba.fastjson.JSONObject;
import com.alipay.AliAppPayRequest;
import com.alipay.config.AlipayConfig;
import com.alipay.enums.AliAppPayResponseCode;
import com.alipay.enums.AliPayPublicCode;
import com.leopard.util.bean.Message;
import com.leopard.util.enums.SystemCodeAndMsg;
 
/**
 * ali支付
 */
@RestController
@RequestMapping(value = "/alipay")
public class AliPayAction {
 
  private static final Logger logger = LoggerFactory.getLogger(AliPayAction.class);
 
  /**
   * 请求生成订单签名信息
   * 
   * @param subject
   *            标题
   * @param body
   *            内容
   * @param totalAmount
   *            金额
   * @param passbackParams
   *            附加参数
   * @return
   */
  @RequestMapping(value = "/getModelOrderInfoSign", method = RequestMethod.POST)
  public Message getModelOrderInfoSign(@RequestParam(value = "subject") String subject,
      @RequestParam(value = "body") String body, @RequestParam(value = "totalAmount") String totalAmount,
      @RequestParam(value = "passbackParams") String passbackParams) {
 
    AliAppPayResponseCode appPayRequest = new AliAppPayRequest().appPayRequest(30, subject, body, totalAmount,
        "201910221548751212", passbackParams, "http://cwfpx6.natappfree.cc/verifyOrderInfoSign");
    // AliAppPayResponseCode appPayRequest = new
    // AliAppPayRequest().appPayRequest(30, "测试-model", "预约3天,详情如下。。。",
    // "0.01", "201910221548751212", "paramUrl;paramUrl2",
    // "http://cwfpx6.natappfree.cc/verifyOrderInfoSign");
    return new Message("200", "aa", appPayRequest.alias());
  }
 
  /**
   * 同步获取前端成功返回结果
   * 
   * @param result
   *            支付成功后的result的json串
   * @return
   */
  @RequestMapping(value = "/syncNotifyValidate", method = RequestMethod.POST)
  public Message syncNotifyValidate(@RequestParam(value = "result") String result) {
 
    JSONObject resultObject = JSONObject.parseObject(result);
    String alipayTradeAppPayResponse = resultObject.getString("alipay_trade_app_pay_response");
    if (StringUtils.isBlank(alipayTradeAppPayResponse)) {
      return new Message(SystemCodeAndMsg.FAIL.code(), "响应参数不存在");
    }
    String sign = resultObject.getString("sign");
    if (StringUtils.isBlank(sign)) {
      return new Message(SystemCodeAndMsg.FAIL.code(), "验签信息不能为空");
    }
    String signType = resultObject.getString("sign_type");
    if (!AlipayConfig.sign_type.equals(signType)) {
      return new Message(SystemCodeAndMsg.FAIL.code(), "签名类型不匹配");
    }
 
    JSONObject responseObject = JSONObject.parseObject(alipayTradeAppPayResponse);
    if (!AliPayPublicCode.Success.code().equals(responseObject.getString("code"))) {
      logger.info("---syncNotifyValidate-----responseObject:" + responseObject.toString());
      return new Message(responseObject.getString("code"), responseObject.getString("msg"));
    }
 
    // 以下验证业务逻辑需补充
    Message publicValidateBaseInfo = publicValidateBaseInfo(responseObject);
    if(!SystemCodeAndMsg.SUCCESS.code().equals(publicValidateBaseInfo.getCode())){
      //验证失败
      return publicValidateBaseInfo;
    }
 
    // 验证通过,买家付款成功,将信息记录到数据库
    // 业务代码
 
    // 反馈给前端
    return new Message(SystemCodeAndMsg.SUCCESS.code(), SystemCodeAndMsg.SUCCESS.msg());
  }
 
  /**
   * 异步获取支付宝POST通知。此地址是一开始生成订单传入的异步地址,请保留好路径
   * 
   * @param request
   * @return
   */
  @RequestMapping(value = "/asynNotifyValidate", method = RequestMethod.POST)
  public String asynNotifyValidate(HttpServletRequest request) {
 
    // 支付宝提供的验签方法,已经封装到依赖包,请求调用就行
    AliAppPayResponseCode verifyOrderInfoSign = new AliAppPayRequest().verifyOrderInfoSign(request);
    if (!AliAppPayResponseCode.SUCCESS.code().equals(verifyOrderInfoSign.code())) {
      return "failure";
    }
    
    // 以下验证业务逻辑需补充
    // 已经将验证过程中的订单信息和响应信息放入到alias内回传回来
    JSONObject verifyOrderInfoJson = JSONObject.parseObject(verifyOrderInfoSign.alias());
    Message publicValidateBaseInfo = publicValidateBaseInfo(verifyOrderInfoJson);
    if(!SystemCodeAndMsg.SUCCESS.code().equals(publicValidateBaseInfo.getCode())){
      //验证失败
      return "failure";
    }
    
    //验证通过,开始业务代码,并标记订单支付成功,该信息可覆盖同步回调信息,较为准确
    //最好将回调信息都保存在数据库做记录
    //verifyOrderInfoJson已经保存好回调数据,直接放入数据库用保存即可
 
    return "success";
  }
 
  /**
   * 支付宝公用回调信息验签
   * 
   * @param jsonObject
   * @return
   */
  private Message publicValidateBaseInfo(JSONObject jsonObject) {
    
    // 1、商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号;
    String outTradeNo = jsonObject.getString("out_trade_no");
    // 业务查找订单号对应的信息,并进行匹配验证
 
    // 2、判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额);
    String totalAmount = jsonObject.getString("total_amount");
    // 根据1获取到的信息,进行匹配验证
 
    // 3、校验通知中的 seller_id(或者 seller_email) 是否为 out_trade_no
    // 这笔单据对应的操作方(有的时候,一个商户可能有多个 seller_id/seller_email);
    String sellerId = jsonObject.getString("seller_id");
    if (!AliAppPayRequest.verifySellerId(sellerId)) {
      logger.info("---publicValidateBaseInfo-----verifySellerId:" + jsonObject.toString());
      return new Message(SystemCodeAndMsg.FAIL.code(), "验证信息有误");
    }
 
    // 4、验证 app_id
    // 是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明同步校验结果是无效的,只有全部验证通过后,才可以认定买家付款成功。
    String appId = jsonObject.getString("app_id");
    if (!AliAppPayRequest.verifyAppId(appId)) {
      logger.info("---publicValidateBaseInfo-----verifyAppId:" + jsonObject.toString());
      return new Message(SystemCodeAndMsg.FAIL.code(), "验证信息有误");
    }
    
    return new Message(SystemCodeAndMsg.SUCCESS.code(), SystemCodeAndMsg.SUCCESS.msg());
  }
}

六、调试应用

支付能力直接涉及到交易与资金,为了方便开放者调试支付能力,我们已经准备好沙箱环境,包括沙箱环境账号和沙箱版支付宝钱包,这样就可以在沙箱环境调试了。具体操作步骤见沙箱联调指南。

七、生产联调

小金额调试

1、

uniapp/手机APP使用支付宝支付(服务端)_第4张图片

2、

uniapp/手机APP使用支付宝支付(服务端)_第5张图片

更多细节可以加入知识星球向我提问。可以让你少走弯路哦!

你可能感兴趣的:(SpringBoot,uni-app)