第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读

这篇具有很好参考价值的文章主要介绍了第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要

本节首先会讲解商户证书、私钥、微信平台证书的获取、APIv3密钥的生成。然后将我们微信支付需要的参数配置信息初始化出来,为后面的业务代码使用。结合微信平台证书下载案例和微信统一下单api来讲解请求和响应都做了什么操作。上一节中我们提到的那些证书又是如何应用在接口中的。最后再讲一下如何做内外网穿透。

证书获取

微信平台证书获取

为确保 API 请求过程中的安全性,客户端需要使用微信支付平台证书来验证服务器响应的真实性和完整性。微信平台证书需要我们下载来使用,主要应用场景是商户用来验证签名、微信侧来解密数据使用。服务端的sdk已经为我们提供了下载证书的api。打开服务端sdk的源码地址:https://github.com/wechatpay-apiv3/wechatpay-java,我们可以通过手动或自动下载证书的方式来获取微信平台证书,如果我们使用的自动下载证书 从 v0.2.3 版本开始,sdk中引入了一个名为 RSAAutoCertificateConfig 的配置类,用于自动更新平台证书。

RSAAutoCertificateConfig 会利用 AutoCertificateService 自动下载微信支付平台证书。 AutoCertificateService 将启动一个后台线程,定期(目前为每60分钟)更新证书,以实现证书过期时的平滑切换。在每次构建 RSAAutoCertificateConfig 时,SDK 首先会使用传入的商户参数下载一次微信支付平台证书。 如果下载成功,SDK 会将商户参数注册或更新至 AutoCertificateService。若下载失败,将会抛出异常。

为了提高性能,建议将配置类作为全局变量。 复用 RSAAutoCertificateConfig 可以减少不必要的证书下载,避免资源浪费。 只有在配置发生变更时,才需要重新构造 RSAAutoCertificateConfig。如果您有多个商户号,可以为每个商户构建相应的 RSAAutoCertificateConfig。为了保证是全局唯一,下面我们来初始化一个全局配置类,我们使用单例模式来自动更新证书代码如下:创建一个WxInitUtils.java文件,添加如下代码:

//商户的全局配置类
    private static Config instance;                                             

    /**
     * 定义商户的全局配置信息,要求一个商户号对应一个配置
     * 不能重复生成配置
     * RSAAutoCertificateConfig 会利用 AutoCertificateService 自动下载微信支付平台证书。
     * AutoCertificateService 将启动一个后台线程,定期(目前为每60分钟)更新证书,
     * 以实现证书过期时的平滑切换。
     * 在每次构建 RSAAutoCertificateConfig 时,
     * SDK 首先会使用传入的商户参数下载一次微信支付平台证书。 如果下载成功,SDK 会将商户参数注册或更
     * 新至 AutoCertificateService。若下载失败,将会抛出异常。
     * 为了提高性能,建议将配置类作为全局变量。 复用 RSAAutoCertificateConfig
     * 可以减少不必要的证书下载,避免资源浪费。 只有在配置发生变更时,
     * 才需要重新构造 RSAAutoCertificateConfig。
     */
    public static Config getInstance(WxPayConfig wxPayConfig){
        if (instance == null){
            //如果实例不存在,创建一个新的实例
            synchronized (WxPayConfig.class){
                //双重检查锁定,防止多线程竞争时创建多个实例
                if (instance == null){
                    try{
                        if(wxPayConfig == null){
                            log.info("配置信息加载出错===");
                            return null;
                        }
                        log.info("商户号为==="+ wxPayConfig.getMchId());
                        log.info("商户私钥串为==="+ wxPayConfig.getPrivateKey());
                        log.info("序列号为==="+ wxPayConfig.getMchSerialNo());
                        log.info("密钥为==="+ wxPayConfig.getApiV3Key());
                        instance =  new RSAAutoCertificateConfig.Builder()
                                .merchantId(wxPayConfig.getMchId())
                                .privateKey(wxPayConfig.getPrivateKey())
//                                .privateKeyFromPath(wxPayConfig.getPrivateKeyPath())
                                .merchantSerialNumber(wxPayConfig.getMchSerialNo())
                                .apiV3Key(wxPayConfig.getApiV3Key())
                                .build();
                    }catch (Exception e){
                        e.printStackTrace();
                        log.error("构建商户配置信息出错,错误信息为"+e.getMessage());
                        return null;
                    }
                }
            }
        }
        return instance;
    }

上述代码instance实例只会初始化一次。调用getInstance方法并传入我们申请证书信息即可完成证书的自动更新和下载。

接下来我们从源码分析的角度上来分析一下证书的下载过程,分析下载过程主要目的是看看上一节的密钥证书是如何应用的。我们重点来分析这段代码块:

 instance =  new RSAAutoCertificateConfig.Builder()               
                                .merchantId(wxPayConfig.getMchId())
                                .privateKey(wxPayConfig.getPrivateKey())
                                .merchantSerialNumber(wxPayConfig.getMchSerialNo())
                                .apiV3Key(wxPayConfig.getApiV3Key())
                                .build();

使用 new RSAAutoCertificateConfig.Builder() 拿到其内部静态类Builder,Builder类继承了抽象类 AbstractRSAConfigBuilder,并调用父类的方法来初始化商户信息放到AbstractRSAConfigBuilder配置类中。调用其内部的build方法构造RSAAutoCertificateProvider.Builder类,同时将商户信息存储到RSAAutoCertificateProvider中,并调用build()方法来下载证书,下载证书的具体步骤:
1、首先租组装商户的签名信息(包括商户证书的序列号、商户私钥、商户号)如下代码段:

       credential =
              new WechatPay2Credential(
                  requireNonNull(merchantId),
                  new RSASigner(requireNonNull(merchantSerialNumber), privateKey));
        }

2、构造httpClient,并将商户证书、签名签证器设置到httpclient中。
3、请求微信平台的证书下载地址,进行证书下载,构造证书下载器:

 CertificateDownloader downloader =
        new CertificateDownloader.Builder()
            .certificateHandler(rsaCertificateHandler)
            .downloadUrl(REQUEST_URL)
            .aeadCipher(aeadCipher)
            .httpClient(httpClient)
            .build();

其中 REQUEST_URL = "https://api.mch.weixin.qq.com/v3/certificates?algorithm_type=RSA" , aeadCipher 为APIv3密钥。构造的httpClient
4、证书下载:

  /**
   * 注册证书下载任务 如果是第一次注册,会先下载证书。如果能成功下载,再保存下载器,供定时更新证书使用。如果下载失败,会抛出异常。
   * 如果已经注册过,当前传入的下载器将覆盖之前的下载器。如果当前下载器不能下载证书,定时更新证书会失败。
   *
   * @param merchantId 商户号
   * @param type 调用方自定义的证书类型,例如 RSA/ShangMi
   * @param downloader 证书下载器
   */
  public static void register(String merchantId, String type, CertificateDownloader downloader) {
    String key = calculateDownloadWorkerMapKey(merchantId, type);
    Runnable worker =
        () -> {
          Map<String, X509Certificate> result = downloader.download();
          certificateMap.put(key, result);
        };

    // 下载证书,以验证配置是正确的
    // 如果错误将抛出异常,fast-fail
    worker.run();
    // 更新配置
    downloadWorkerMap.put(key, worker);

    start(defaultUpdateInterval);
  }

打开download方法:

  /** 下载证书 */
  public Map<String, X509Certificate> download() {        
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.GET)
            .url(downloadUrl)
            .addHeader(Constant.ACCEPT, " */*")
            .addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue())
            .build();
    HttpResponse<DownloadCertificateResponse> httpResponse =
        httpClient.execute(httpRequest, DownloadCertificateResponse.class);

    Map<String, X509Certificate> downloaded = decryptCertificate(httpResponse);
    validateCertificate(downloaded);
    return downloaded;
  }

这里大家注意,重点来了,在下载证书时,sdk将签名封装到了httpClient中,在 HttpResponse<DownloadCertificateResponse> httpResponse = httpClient.execute(httpRequest, DownloadCertificateResponse.class); 这段代码中的execute方法中通过构造token值,并将token放到请求的header中,重点看这个方法getAuthorization(httpRequest) 这个方法中,使用了商户的私钥将请求body进行签名,并将明文、商户的公钥、签名信息组成token串发送给了微信平台,具体构造token的代码块为:

 String token =
        "mchid=\""
            + getMerchantId()
            + "\","
            + "nonce_str=\""
            + nonceStr
            + "\","
            + "timestamp=\""
            + timestamp
            + "\","
            + "serial_no=\""
            + signature.getCertificateSerialNumber()
            + "\","
            + "signature=\""
            + signature.getSign()
            + "\"";

请求完成后,微信平台侧会实时将响应数据返回。在商户侧调用decryptCertificate(httpResponse) 将响应的数据进行解密,解密时使用我们之前设置的APIv3密钥。紧接着会验证下载证书的有效性会调用 validateCertificate(downloaded);具体的验证代码段如下:

 PKIXParameters params = new PKIXParameters(trustAnchor);
      params.setRevocationEnabled(false);

      List<X509Certificate> certs = new ArrayList<>();
      certs.add(certificate);

      CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
      CertPath certPath = cf.generateCertPath(certs);

      CertPathValidator validator = CertPathValidator.getInstance("PKIX");
      validator.validate(certPath, params);

上述代码块用于检查证书是否由可信的根证书颁发,以及证书是否有效。X509Certificate是一种常用的数字证书标准。首先创建一个 PKIXParameters 类型的对象,它是一个用于验证证书路径的参数集合,它的构造器需要一个 trustAnchor 参数,表示可信的根证书,它是一个 Set 类型的对象,它包含了一个或多个根证书的信息。 getInstance(“PKIX”) 返回一个支持 PKIX(公钥基础设施)算法的验证器实例。

证书下载完成会存放到 AutoCertificateService类certificateMap中 ,certificateMap 是一个ConcurrentHashMap ,是线程安全的,可以支持多线程的并发访问和修改,而AutoCertificateService类是一个定时更新证书的服务,它是一个由静态函数构成的工具类。

private static final ConcurrentHashMap<String, Map<String, X509Certificate>> certificateMap =       
      new ConcurrentHashMap<>();
Map<String, X509Certificate> result = downloader.download();                       
certificateMap.put(key, result);

到此微信平台证书的自动下载过程就描述清楚了,下面我们来总结一下具体流程:

(1)商户侧包装商户信息:商户号、商户公钥、商户私钥等信息,并将请求的数据进行签名。将签名和公钥、时间戳、随机数等信息打包成token放到请求头部发送至微信平台侧。
(2)微信测收到请求后获取到认证token,并解析出商户公钥和明文信息,对数据进行验签。同时使用APIv3密钥将证书进行加密同步返回给商户侧。
(3)商户侧收到微信侧的响应数据后,从响应数据解密出证书,应答报文解密后,生成X.509证书对象,也就是将证书从String转为X509Certificate。
(4)验证证书的有效性
(5)将证书存储到AutoCertificateService中的certificateMap 中。

APIv3密钥设置

在商户平台中【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - APIv3密钥设置】,这个可使用在线生成器生成地址:https://www.bchrt.com/tools/suijimima/

商户平台证书和私钥的获取

以下内容来自微信官网:https://kf.qq.com/faq/161222NneAJf161222U7fARv.html
1、登录【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - 申请API证书】申请证书,确定后请勿关闭页面
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
2、点击下载证书工具;下载后,双击“WXCertUtil.exe”文件,选择安装路径后,点击申请证书

也可通过以下链接下载证书工具:

windows版本
mac版本

3、在【证书工具】,填写商户号信息(商户号、商户名称),点击下一步
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
4、在【证书工具】,复制证书请求串
(若提示"请粘贴请求串到商户平台获取证书串",请在第5点步骤检查是否已粘贴。可同时尝试手动鼠标复制粘贴的方法)
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
5、在【商户平台】,粘贴证书请求串
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
6、在【商户平台】,输入操作密码,安全验证后生成证书串
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
7、在【商户平台】,复制证书串
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
8、在【证书工具】,粘贴证书串,点击下一步,申请证书成功
(若提示"证书与本地公私钥不匹配",可能是浏览器禁用了剪切板复制功能。请在操作步骤第7点,操作时使用鼠标选中全部证书串内容(注意右边有下拉框),单击鼠标右键选择复制)
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读,项目支付功能实战专栏,微信,安全,java
提醒:请将生成的证书文件转交给技术人员,由技术人员将证书部署到服务器上(请务必妥善保管证书及私钥,因为私钥文件只能通过证书工具导出,若私钥丢失,则无法找回,只能作废后重新申请。)

9、证书申请成功后,在证书文件夹中解压文件会发现有3个文件:.p12 这个不用管,其中两个文件apiclient_cert.pem(商户公钥文件)、apiclient_key(商户私钥文件)。

到此,商户API证书已经获取完毕。

初始化微信配置

为了统一配置微信支付用到的信息,我们在项目的resource目录下创建一个配置文件wxpay.properties

# 商户号
wxpay.mch-id=xxxxxxx
# 微信商户证书序列号                                                                           
wxpay.mch-serial-no=xxxxxxxxxxxxxxxxxxx
# 商户私钥(路径加载方式使用)
wxpay.private-key-path=apiclient_key.pem
# APIv3密钥
wxpay.api-v3-key=xxxxxxxxxxxxxx
# 小程序APPID
wxpay.appid=xxxxxxxxxxx
# 微信小程序密钥
wxpay.appSecret=xxxxxxxxxxxxxxxxxxxxxxxxx
# 微信商户平台域名(调用接口时的通用域名)
wxpay.domain=https://api.mch.weixin.qq.com
#微信支付回调地址域名(需要https 并且为备案的域名)
wxpay.notify-domain=https://test.notify.com
#商户私钥
wxpay.private-key=-----BEGIN PRIVATE KEY-----xxxx-----END PRIVATE KEY-----                                  

其对应的配置类如下:

@Configuration
@PropertySource("classpath:wxpay.properties") //读取配置文件
@ConfigurationProperties(prefix="wxpay") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
public class WxPayConfig {

    // 商户号
    private  String mchId;

    // 商户API证书序列号
    private  String mchSerialNo;  

    // 商户私钥文件
    private  String privateKeyPath;

    // APIv3密钥
    private  String apiV3Key;

    // APPID
    private String appid;
    //小程序密钥
    private String appSecret;
    // 微信服务器地址
    private String domain;

    // 接收结果通知地址
    private String notifyDomain;

    // APIv2密钥
    private String partnerKey;

    //商户私钥字符串
    private String privateKey;
}

小程序统一下单

本节,主要来以分析小程序统一下单的案例,来说明sdk的使用方式,以及商户证书和平台证书的在调用下单接口时是如何使用的,本节不会过多在当前项目中展开业务代码,只讲解下单接口如何调用,安全验证的过程。

在调用小程序下单接口之前,首先要创建订单数据,调用下单接口时将订单数据传过去,比如订单金额、商品id、订单编号等。微信收到订单后会返回预付订单id以及微信平台返回的微信订单信息,下面来看看具体的调用代码,下面是小程序下单的代码块。

  if (config == null){         
            config = WxInitUtils.getInstance(wxPayConfig);
  }
 JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 填充预下单参数
        PrepayRequest request = new PrepayRequest();
        //appid
        request.setAppid(wxPayConfig.getAppid());
        //商户id
        request.setMchid(wxPayConfig.getMchId());
        //产品描述
        assert orderInfo != null;
        request.setDescription(orderInfo.getOrderTitle());
        //商户订单号
        request.setOutTradeNo(orderInfo.getOrderNo());
        //通知url
        request.setNotifyUrl(wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));     

        //金额信息
        Amount amount = new Amount();
        amount.setTotal(orderInfo.getTotalFee());
        amount.setCurrency("CNY");
        request.setAmount(amount);

        //用户信息
        Payer payer = new Payer();
        payer.setOpenid(openId.toString());
        request.setPayer(payer);

        log.info("请求参数 ===> {}" + request.toString());
        PrepayWithRequestPaymentResponse response = null;

        try {
            // response包含了调起支付所需的所有参数,可直接用于前端调起支付
            response = service.prepayWithRequestPayment(request);
        } catch (Exception e) {
            log.error("请求下单失败,错误信息" + e.getMessage());
            throw new RuntimeException("请求下单失败,错误信息" + e.getMessage());
        }

        //处理返回值
        assert response != null;
        String packageVal = response.getPackageVal();
        String prepayId = packageVal;

上述代码中,首先拿到配置信息config,然后调用JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build(); 这个是sdk提供的api,接下来组装好参数之间向微信发起请求,请求的代码段response = service.prepayWithRequestPayment(request); 在prepayWithRequestPayment方法中调用了String prepayId = this.jsapiService.prepay(request).getPrepayId(); 在prepay方法中才是真正的发起请求,重点来看下请求的代码段:

HttpRequest httpRequest = (new HttpRequest.Builder()).httpMethod(HttpMethod.POST).url(requestPath).headers(headers).body(this.createRequestBody(request)).build();
HttpResponse<PrepayResponse> httpResponse = this.httpClient.execute(httpRequest, PrepayResponse.class);

在execute方法中又调用了如下代码,和下载证书的接口调用是一样的。

 HttpRequest innerRequest =
        new Builder()
            .url(httpRequest.getUrl())
            .httpMethod(httpRequest.getHttpMethod())
            .headers(httpRequest.getHeaders())
            .addHeader(AUTHORIZATION, getAuthorization(httpRequest))
            .addHeader(USER_AGENT, getUserAgent())
            .body(httpRequest.getBody())
            .build();
    OriginalResponse originalResponse = innerExecute(innerRequest);       
    validateResponse(originalResponse);

重点来关注Authorization, 的组成如下:

Authorization: 认证类型 签名信息

具体组成为:
认证类型: 目前为WECHATPAY2-SHA256-RSA2048
签名信息
发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
商户API证书序列号serial_no,用于声明所使用的证书
请求随机串nonce_str
时间戳timestamp
签名值signature

示例如下:

‘Authorization: WECHATPAY2-SHA256-RSA2048 mchid=“1900009191”,nonce_str=“593BEC0C930BF1AFEB40B4A08C8FB242”,signature=“uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==”,timestamp=“1554208460”,serial_no=“1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C”’

以上就是签名的过程,使用商户私钥签名,签名后之间发送到了微信平台,所以小程序统一下单,并没有加密的操作,只有签名的操作。同样微信同步响应后,也需要在商户侧进行验签。

sdk中验签的代码段如下:

 String timestamp = responseHeaders.getHeader(WECHAT_PAY_TIMESTAMP);       
    try  {
      Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp)); 
      // 拒绝过期请求
      if (Duration.between(responseTime, Instant.now()).abs().toMinutes() 
          >= RESPONSE_EXPIRED_MINUTES) { 
        throw new IllegalArgumentException(
            String.format(
                "Validate http response,timestamp[%s] of httpResponse is expires, " 
                    + "request-id[%s]", 
                timestamp, responseHeaders.getHeader(REQUEST_ID)));
      }
    } catch (DateTimeException | NumberFormatException e) { 
      throw new IllegalArgumentException(
          String.format(
              "Validate http response,timestamp[%s] of httpResponse is invalid, request-id[%s]", 
              timestamp, responseHeaders.getHeader(REQUEST_ID)));
    }
    String message = 
        timestamp
            + "\n"
            + responseHeaders.getHeader(WECHAT_PAY_NONCE) 
            + "\n"
            + (responseBody == null ? "" : responseBody)
            + "\n";
    logger.debug("Message for verifying signatures is[{}]", message); 
    String serialNumber = responseHeaders.getHeader(WECHAT_PAY_SERIAL);
    logger.debug("SerialNumber for verifying signatures is[{}]", serialNumber); 
    String signature = responseHeaders.getHeader(WECHAT_PAY_SIGNATURE); 
    logger.debug("Signature for verifying signatures is[{}]", signature); 
    return verifier.verify(serialNumber, message, signature);

验证签名要经过以下几个步骤:
(1)校验微信响应的时间戳是否过期,有效时间为5分钟,// 拒绝过期请求
if (Duration.between(responseTime, Instant.now()).abs().toMinutes()
>= RESPONSE_EXPIRED_MINUTES) 目的是防止重放攻击,重放攻击 是指攻击者截取报文及其签名,并以恶意或欺诈目的重新传输数据的一种攻击手段。 为了降低此类攻击的风险,微信支付在 HTTP 头 Wechatpay-Timestamp 中提供了生成签名的时间戳。若微信支付需要重新发送某个通知回调,我们也会重新生成相应的时间戳和签名。在验证签名之前,商户系统应检查时间戳是否已过期。我们建议商户系统允许最多5分钟的时间偏差。如果时间戳与当前时间的偏差超过5分钟,您应拒绝处理当前的响应或回调通知。

(2)构造验签名串
构造验签名串由3个部分组成 ,应答或通知回调中获取以下信息:
HTTP 头 Wechatpay-Timestamp 中的应答时间戳
HTTP 头 Wechatpay-Nonce 中的应答随机串
应答报文主体(Response Body),请使用原始报文主体执行验签。如果您使用了某个框架,要确保它不会篡改报文主体。对报文主体的任何篡改都会导致验证失败。

(3)验证微信平台证书是否正确
检查 HTTP 头 Wechatpay-Serial 的内容是否跟商户当前所持有的微信支付平台证书的序列号一致。若不一致,请重新获取证书。否则,签名的私钥和证书不匹配,将验证失败。重点代码如下:根据头部返回的证书序列号查询下载时存放的证书是否一致。

  /**
   * 根据证书序列号获取证书
   *
   * @param serialNumber 微信支付平台证书序列号
   * @return X.509证书实例
   */
  @Override
  public X509Certificate getCertificate(String serialNumber) {
    return AutoCertificateService.getCertificate(merchantId, ALGORITHM_TYPE, serialNumber);
  }

以上就是小程序下单的加签、验签过程,复杂的过程都封装到了sdk中,我们可以不做过多的关注,但是一定要清楚其中的原理,可以发现,下单的过程并没有加密、解密的逻辑。文章来源地址https://www.toymoban.com/news/detail-777693.html

到了这里,关于第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序第五节——登录那些事儿(超详细的前后端完整流程)

    📌 微信小程序第一节 ——自定义顶部、底部导航栏以及获取胶囊体位置信息。 📌 微信小程序第二节 —— 自定义组件 📌 微信小程序第三节 —— 页面跳转的那些事儿 📌 微信小程序第四节—— 网络请求那些事儿 😜 作           者 :是江迪呀 ✒️ 本文 : 微

    2024年02月09日
    浏览(42)
  • Springboot----项目整合微信支付(获取支付二维码)

    个人简介 : 📦个人主页:赵四司机 🏆学习方向:JAVA后端开发 📣种一棵树最好的时间是十年前,其次是现在! 🧡喜欢的话麻烦点点关注喔,你们的支持是我的最大动力。 前言 目前更新的是Springboot项目整合微信支付系列的文章,可以在我的主页中找到该系列其他文章,这

    2024年02月05日
    浏览(41)
  • HCIA-第五节(0606)

    路由器的转发原理-----当数据包进入路由器,路由器将基于数据包中目标IP地址,查询本地的路由表,如果路由器中存在记录,则将无条件按照记录转发。如果路由器没有记录,则将直接丢弃该数据包。 路由表建立的主要目标是为了实现路由协议和静态路由选择。 chenliqidisp

    2024年02月11日
    浏览(49)
  • HCIP第五节------------------------------------------ospf

    运行距离矢量路由协议的路由器周期性地泛洪自己的路由表。通过路由的交互,每台路由器都从相邻的路由器学习到路由,并且加载进自己的路由表中,然后再通告给其他相邻路由器。 对于网络中的所有路由器而言,路由器并不清楚网络的拓扑,只是简单的知道要去往某个目

    2024年02月12日
    浏览(49)
  • Matlab绘图(第五节-三维曲面)

    具体讲述了三维曲面绘图方法等。 此时所有点坐标可以表示为: x=[2 2 2 2 2 2;3 3 3 3 3 3;4 4 4 4 4 4;5 5 5 5 5 5;6 6 6 6 6 6] y=[3 4 5 6 7 8;3 4 5 6 7 8;3 4 5 6 7 8;3 4 5 6 7 8;3 4 5 6 7 8] 矩阵x,y就是该平面内的网格坐标矩阵。 (1)利用矩阵运算生成 (2)利用meshgrid函数生成 [X,Y]=meshgrid(x,y); 其中,

    2023年04月14日
    浏览(50)
  • Verilog 学习第五节(串口发送部分)

    1:串口通信模块设计的目的是用来发送数据的,因此需要有一个数据输入端口 2:串口通信,支持不同的波特率,所以需要一个 波特率设置端口 3:串口通信的本质就是将8位并行数据通过一根信号线,在不同的时刻传输并行数据的不同位,通过多个时刻,最终将8位并行数据

    2023年04月26日
    浏览(42)
  • 【数据结构初阶】第五节.栈的详讲

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、栈的基本认识 二、栈模拟实现:  三、栈的实战演练 3.1 有效的括号 3.2 逆波兰表达式 3.3 栈的压入、弹出序列 总结 上一节内容我们学习了链表的有关内容,今天我们将进行栈的学习

    2023年04月23日
    浏览(48)
  • 【Git 入门教程】第五节、Git远程仓库

    Git是一种分布式版本控制系统,它允许开发者在不同计算机之间协作并共享代码。在本文中,我们将介绍如何以Git为基础进行远程协作。其中包括克隆仓库、推送代码、拉取代码等操作。 要协作开发一个Git项目,需要从服务器上获取该项目的副本。 运行以下命令来克隆Git仓

    2024年02月01日
    浏览(52)
  • 【测试开发】第五节.测试——自动化测试(Selenium工具)

    作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:Java测试开发 每日一句: 人的一生,可以有所作为的时机只有一次,那就是现在!!! 前言 一、自动化测试的概念以及分类 二、Selenium—web自动化测试工具 2.1 自动化测试的一些前置工作 2.2 第一个自动化实例

    2024年02月04日
    浏览(63)
  • 第五节 zookeeper集群与分布式锁_2

    1)要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁。 线程锁 :主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。 线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,

    2024年02月19日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包