国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀

這篇具有很好參考價值的文章主要介紹了第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

摘要

本節(jié)首先會講解商戶證書、私鑰、微信平臺證書的獲取、APIv3密鑰的生成。然后將我們微信支付需要的參數(shù)配置信息初始化出來,為后面的業(yè)務(wù)代碼使用。結(jié)合微信平臺證書下載案例和微信統(tǒng)一下單api來講解請求和響應(yīng)都做了什么操作。上一節(jié)中我們提到的那些證書又是如何應(yīng)用在接口中的。最后再講一下如何做內(nèi)外網(wǎng)穿透。

證書獲取

微信平臺證書獲取

為確保 API 請求過程中的安全性,客戶端需要使用微信支付平臺證書來驗(yàn)證服務(wù)器響應(yīng)的真實(shí)性和完整性。微信平臺證書需要我們下載來使用,主要應(yīng)用場景是商戶用來驗(yàn)證簽名、微信側(cè)來解密數(shù)據(jù)使用。服務(wù)端的sdk已經(jīng)為我們提供了下載證書的api。打開服務(wù)端sdk的源碼地址:https://github.com/wechatpay-apiv3/wechatpay-java,我們可以通過手動或自動下載證書的方式來獲取微信平臺證書,如果我們使用的自動下載證書 從 v0.2.3 版本開始,sdk中引入了一個名為 RSAAutoCertificateConfig 的配置類,用于自動更新平臺證書。

RSAAutoCertificateConfig 會利用 AutoCertificateService 自動下載微信支付平臺證書。 AutoCertificateService 將啟動一個后臺線程,定期(目前為每60分鐘)更新證書,以實(shí)現(xiàn)證書過期時的平滑切換。在每次構(gòu)建 RSAAutoCertificateConfig 時,SDK 首先會使用傳入的商戶參數(shù)下載一次微信支付平臺證書。 如果下載成功,SDK 會將商戶參數(shù)注冊或更新至 AutoCertificateService。若下載失敗,將會拋出異常。

為了提高性能,建議將配置類作為全局變量。 復(fù)用 RSAAutoCertificateConfig 可以減少不必要的證書下載,避免資源浪費(fèi)。 只有在配置發(fā)生變更時,才需要重新構(gòu)造 RSAAutoCertificateConfig。如果您有多個商戶號,可以為每個商戶構(gòu)建相應(yīng)的 RSAAutoCertificateConfig。為了保證是全局唯一,下面我們來初始化一個全局配置類,我們使用單例模式來自動更新證書代碼如下:創(chuàng)建一個WxInitUtils.java文件,添加如下代碼:

//商戶的全局配置類
    private static Config instance;                                             

    /**
     * 定義商戶的全局配置信息,要求一個商戶號對應(yīng)一個配置
     * 不能重復(fù)生成配置
     * RSAAutoCertificateConfig 會利用 AutoCertificateService 自動下載微信支付平臺證書。
     * AutoCertificateService 將啟動一個后臺線程,定期(目前為每60分鐘)更新證書,
     * 以實(shí)現(xiàn)證書過期時的平滑切換。
     * 在每次構(gòu)建 RSAAutoCertificateConfig 時,
     * SDK 首先會使用傳入的商戶參數(shù)下載一次微信支付平臺證書。 如果下載成功,SDK 會將商戶參數(shù)注冊或更
     * 新至 AutoCertificateService。若下載失敗,將會拋出異常。
     * 為了提高性能,建議將配置類作為全局變量。 復(fù)用 RSAAutoCertificateConfig
     * 可以減少不必要的證書下載,避免資源浪費(fèi)。 只有在配置發(fā)生變更時,
     * 才需要重新構(gòu)造 RSAAutoCertificateConfig。
     */
    public static Config getInstance(WxPayConfig wxPayConfig){
        if (instance == null){
            //如果實(shí)例不存在,創(chuàng)建一個新的實(shí)例
            synchronized (WxPayConfig.class){
                //雙重檢查鎖定,防止多線程競爭時創(chuàng)建多個實(shí)例
                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("構(gòu)建商戶配置信息出錯,錯誤信息為"+e.getMessage());
                        return null;
                    }
                }
            }
        }
        return instance;
    }

上述代碼instance實(shí)例只會初始化一次。調(diào)用getInstance方法并傳入我們申請證書信息即可完成證書的自動更新和下載。

接下來我們從源碼分析的角度上來分析一下證書的下載過程,分析下載過程主要目的是看看上一節(jié)的密鑰證書是如何應(yīng)用的。我們重點(diǎn)來分析這段代碼塊:

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

使用 new RSAAutoCertificateConfig.Builder() 拿到其內(nèi)部靜態(tài)類Builder,Builder類繼承了抽象類 AbstractRSAConfigBuilder,并調(diào)用父類的方法來初始化商戶信息放到AbstractRSAConfigBuilder配置類中。調(diào)用其內(nèi)部的build方法構(gòu)造RSAAutoCertificateProvider.Builder類,同時將商戶信息存儲到RSAAutoCertificateProvider中,并調(diào)用build()方法來下載證書,下載證書的具體步驟:
1、首先租組裝商戶的簽名信息(包括商戶證書的序列號、商戶私鑰、商戶號)如下代碼段:

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

2、構(gòu)造httpClient,并將商戶證書、簽名簽證器設(shè)置到httpclient中。
3、請求微信平臺的證書下載地址,進(jìn)行證書下載,構(gòu)造證書下載器:

 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密鑰。構(gòu)造的httpClient
4、證書下載:

  /**
   * 注冊證書下載任務(wù) 如果是第一次注冊,會先下載證書。如果能成功下載,再保存下載器,供定時更新證書使用。如果下載失敗,會拋出異常。
   * 如果已經(jīng)注冊過,當(dāng)前傳入的下載器將覆蓋之前的下載器。如果當(dāng)前下載器不能下載證書,定時更新證書會失敗。
   *
   * @param merchantId 商戶號
   * @param type 調(diào)用方自定義的證書類型,例如 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);
        };

    // 下載證書,以驗(yàn)證配置是正確的
    // 如果錯誤將拋出異常,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;
  }

這里大家注意,重點(diǎn)來了,在下載證書時,sdk將簽名封裝到了httpClient中,在 HttpResponse<DownloadCertificateResponse> httpResponse = httpClient.execute(httpRequest, DownloadCertificateResponse.class); 這段代碼中的execute方法中通過構(gòu)造token值,并將token放到請求的header中,重點(diǎn)看這個方法getAuthorization(httpRequest) 這個方法中,使用了商戶的私鑰將請求body進(jìn)行簽名,并將明文、商戶的公鑰、簽名信息組成token串發(fā)送給了微信平臺,具體構(gòu)造token的代碼塊為:

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

請求完成后,微信平臺側(cè)會實(shí)時將響應(yīng)數(shù)據(jù)返回。在商戶側(cè)調(diào)用decryptCertificate(httpResponse) 將響應(yīng)的數(shù)據(jù)進(jìn)行解密,解密時使用我們之前設(shè)置的APIv3密鑰。緊接著會驗(yàn)證下載證書的有效性會調(diào)用 validateCertificate(downloaded);具體的驗(yàn)證代碼段如下:

 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);

上述代碼塊用于檢查證書是否由可信的根證書頒發(fā),以及證書是否有效。X509Certificate是一種常用的數(shù)字證書標(biāo)準(zhǔn)。首先創(chuàng)建一個 PKIXParameters 類型的對象,它是一個用于驗(yàn)證證書路徑的參數(shù)集合,它的構(gòu)造器需要一個 trustAnchor 參數(shù),表示可信的根證書,它是一個 Set 類型的對象,它包含了一個或多個根證書的信息。 getInstance(“PKIX”) 返回一個支持 PKIX(公鑰基礎(chǔ)設(shè)施)算法的驗(yàn)證器實(shí)例。

證書下載完成會存放到 AutoCertificateService類certificateMap中 ,certificateMap 是一個ConcurrentHashMap ,是線程安全的,可以支持多線程的并發(fā)訪問和修改,而AutoCertificateService類是一個定時更新證書的服務(wù),它是一個由靜態(tài)函數(shù)構(gòu)成的工具類。

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

到此微信平臺證書的自動下載過程就描述清楚了,下面我們來總結(jié)一下具體流程:

(1)商戶側(cè)包裝商戶信息:商戶號、商戶公鑰、商戶私鑰等信息,并將請求的數(shù)據(jù)進(jìn)行簽名。將簽名和公鑰、時間戳、隨機(jī)數(shù)等信息打包成token放到請求頭部發(fā)送至微信平臺側(cè)。
(2)微信測收到請求后獲取到認(rèn)證token,并解析出商戶公鑰和明文信息,對數(shù)據(jù)進(jìn)行驗(yàn)簽。同時使用APIv3密鑰將證書進(jìn)行加密同步返回給商戶側(cè)。
(3)商戶側(cè)收到微信側(cè)的響應(yīng)數(shù)據(jù)后,從響應(yīng)數(shù)據(jù)解密出證書,應(yīng)答報文解密后,生成X.509證書對象,也就是將證書從String轉(zhuǎn)為X509Certificate。
(4)驗(yàn)證證書的有效性
(5)將證書存儲到AutoCertificateService中的certificateMap 中。

APIv3密鑰設(shè)置

在商戶平臺中【微信支付商戶平臺 - 賬戶中心 - 賬戶設(shè)置 - API安全 - APIv3密鑰設(shè)置】,這個可使用在線生成器生成地址:https://www.bchrt.com/tools/suijimima/

商戶平臺證書和私鑰的獲取

以下內(nèi)容來自微信官網(wǎng):https://kf.qq.com/faq/161222NneAJf161222U7fARv.html
1、登錄【微信支付商戶平臺 - 賬戶中心 - 賬戶設(shè)置 - API安全 - 申請API證書】申請證書,確定后請勿關(guān)閉頁面
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
2、點(diǎn)擊下載證書工具;下載后,雙擊“WXCertUtil.exe”文件,選擇安裝路徑后,點(diǎn)擊申請證書

也可通過以下鏈接下載證書工具:

windows版本
mac版本

3、在【證書工具】,填寫商戶號信息(商戶號、商戶名稱),點(diǎn)擊下一步
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
4、在【證書工具】,復(fù)制證書請求串
(若提示"請粘貼請求串到商戶平臺獲取證書串",請?jiān)诘?點(diǎn)步驟檢查是否已粘貼??赏瑫r嘗試手動鼠標(biāo)復(fù)制粘貼的方法)
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
5、在【商戶平臺】,粘貼證書請求串
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
6、在【商戶平臺】,輸入操作密碼,安全驗(yàn)證后生成證書串
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
7、在【商戶平臺】,復(fù)制證書串
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
8、在【證書工具】,粘貼證書串,點(diǎn)擊下一步,申請證書成功
(若提示"證書與本地公私鑰不匹配",可能是瀏覽器禁用了剪切板復(fù)制功能。請?jiān)诓僮鞑襟E第7點(diǎn),操作時使用鼠標(biāo)選中全部證書串內(nèi)容(注意右邊有下拉框),單擊鼠標(biāo)右鍵選擇復(fù)制)
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀,項(xiàng)目支付功能實(shí)戰(zhàn)專欄,微信,安全,java
提醒:請將生成的證書文件轉(zhuǎn)交給技術(shù)人員,由技術(shù)人員將證書部署到服務(wù)器上(請務(wù)必妥善保管證書及私鑰,因?yàn)樗借€文件只能通過證書工具導(dǎo)出,若私鑰丟失,則無法找回,只能作廢后重新申請。)

9、證書申請成功后,在證書文件夾中解壓文件會發(fā)現(xiàn)有3個文件:.p12 這個不用管,其中兩個文件apiclient_cert.pem(商戶公鑰文件)、apiclient_key(商戶私鑰文件)。

到此,商戶API證書已經(jīng)獲取完畢。

初始化微信配置

為了統(tǒng)一配置微信支付用到的信息,我們在項(xiàng)目的resource目錄下創(chuàng)建一個配置文件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
# 微信商戶平臺域名(調(diào)用接口時的通用域名)
wxpay.domain=https://api.mch.weixin.qq.com
#微信支付回調(diào)地址域名(需要https 并且為備案的域名)
wxpay.notify-domain=https://test.notify.com
#商戶私鑰
wxpay.private-key=-----BEGIN PRIVATE KEY-----xxxx-----END PRIVATE KEY-----                                  

其對應(yīng)的配置類如下:

@Configuration
@PropertySource("classpath:wxpay.properties") //讀取配置文件
@ConfigurationProperties(prefix="wxpay") //讀取wxpay節(jié)點(diǎn)
@Data //使用set方法將wxpay節(jié)點(diǎn)中的值填充到當(dāng)前類的屬性中
public class WxPayConfig {

    // 商戶號
    private  String mchId;

    // 商戶API證書序列號
    private  String mchSerialNo;  

    // 商戶私鑰文件
    private  String privateKeyPath;

    // APIv3密鑰
    private  String apiV3Key;

    // APPID
    private String appid;
    //小程序密鑰
    private String appSecret;
    // 微信服務(wù)器地址
    private String domain;

    // 接收結(jié)果通知地址
    private String notifyDomain;

    // APIv2密鑰
    private String partnerKey;

    //商戶私鑰字符串
    private String privateKey;
}

小程序統(tǒng)一下單

本節(jié),主要來以分析小程序統(tǒng)一下單的案例,來說明sdk的使用方式,以及商戶證書和平臺證書的在調(diào)用下單接口時是如何使用的,本節(jié)不會過多在當(dāng)前項(xiàng)目中展開業(yè)務(wù)代碼,只講解下單接口如何調(diào)用,安全驗(yàn)證的過程。

在調(diào)用小程序下單接口之前,首先要創(chuàng)建訂單數(shù)據(jù),調(diào)用下單接口時將訂單數(shù)據(jù)傳過去,比如訂單金額、商品id、訂單編號等。微信收到訂單后會返回預(yù)付訂單id以及微信平臺返回的微信訂單信息,下面來看看具體的調(diào)用代碼,下面是小程序下單的代碼塊。

  if (config == null){         
            config = WxInitUtils.getInstance(wxPayConfig);
  }
 JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 填充預(yù)下單參數(shù)
        PrepayRequest request = new PrepayRequest();
        //appid
        request.setAppid(wxPayConfig.getAppid());
        //商戶id
        request.setMchid(wxPayConfig.getMchId());
        //產(chǎn)品描述
        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("請求參數(shù) ===> {}" + request.toString());
        PrepayWithRequestPaymentResponse response = null;

        try {
            // response包含了調(diào)起支付所需的所有參數(shù),可直接用于前端調(diào)起支付
            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,然后調(diào)用JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build(); 這個是sdk提供的api,接下來組裝好參數(shù)之間向微信發(fā)起請求,請求的代碼段response = service.prepayWithRequestPayment(request); 在prepayWithRequestPayment方法中調(diào)用了String prepayId = this.jsapiService.prepay(request).getPrepayId(); 在prepay方法中才是真正的發(fā)起請求,重點(diǎn)來看下請求的代碼段:

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方法中又調(diào)用了如下代碼,和下載證書的接口調(diào)用是一樣的。

 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);

重點(diǎn)來關(guān)注Authorization, 的組成如下:

Authorization: 認(rèn)證類型 簽名信息

具體組成為:
認(rèn)證類型: 目前為WECHATPAY2-SHA256-RSA2048
簽名信息
發(fā)起請求的商戶(包括直連商戶、服務(wù)商或渠道商)的商戶號mchid
商戶API證書序列號serial_no,用于聲明所使用的證書
請求隨機(jī)串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”’

以上就是簽名的過程,使用商戶私鑰簽名,簽名后之間發(fā)送到了微信平臺,所以小程序統(tǒng)一下單,并沒有加密的操作,只有簽名的操作。同樣微信同步響應(yīng)后,也需要在商戶側(cè)進(jìn)行驗(yàn)簽。

sdk中驗(yàn)簽的代碼段如下:

 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);

驗(yàn)證簽名要經(jīng)過以下幾個步驟:
(1)校驗(yàn)微信響應(yīng)的時間戳是否過期,有效時間為5分鐘,// 拒絕過期請求
if (Duration.between(responseTime, Instant.now()).abs().toMinutes()
>= RESPONSE_EXPIRED_MINUTES) 目的是防止重放攻擊,重放攻擊 是指攻擊者截取報文及其簽名,并以惡意或欺詐目的重新傳輸數(shù)據(jù)的一種攻擊手段。 為了降低此類攻擊的風(fēng)險,微信支付在 HTTP 頭 Wechatpay-Timestamp 中提供了生成簽名的時間戳。若微信支付需要重新發(fā)送某個通知回調(diào),我們也會重新生成相應(yīng)的時間戳和簽名。在驗(yàn)證簽名之前,商戶系統(tǒng)應(yīng)檢查時間戳是否已過期。我們建議商戶系統(tǒng)允許最多5分鐘的時間偏差。如果時間戳與當(dāng)前時間的偏差超過5分鐘,您應(yīng)拒絕處理當(dāng)前的響應(yīng)或回調(diào)通知。

(2)構(gòu)造驗(yàn)簽名串
構(gòu)造驗(yàn)簽名串由3個部分組成 ,應(yīng)答或通知回調(diào)中獲取以下信息:
HTTP 頭 Wechatpay-Timestamp 中的應(yīng)答時間戳
HTTP 頭 Wechatpay-Nonce 中的應(yīng)答隨機(jī)串
應(yīng)答報文主體(Response Body),請使用原始報文主體執(zhí)行驗(yàn)簽。如果您使用了某個框架,要確保它不會篡改報文主體。對報文主體的任何篡改都會導(dǎo)致驗(yàn)證失敗。

(3)驗(yàn)證微信平臺證書是否正確
檢查 HTTP 頭 Wechatpay-Serial 的內(nèi)容是否跟商戶當(dāng)前所持有的微信支付平臺證書的序列號一致。若不一致,請重新獲取證書。否則,簽名的私鑰和證書不匹配,將驗(yàn)證失敗。重點(diǎn)代碼如下:根據(jù)頭部返回的證書序列號查詢下載時存放的證書是否一致。

  /**
   * 根據(jù)證書序列號獲取證書
   *
   * @param serialNumber 微信支付平臺證書序列號
   * @return X.509證書實(shí)例
   */
  @Override
  public X509Certificate getCertificate(String serialNumber) {
    return AutoCertificateService.getCertificate(merchantId, ALGORITHM_TYPE, serialNumber);
  }

以上就是小程序下單的加簽、驗(yàn)簽過程,復(fù)雜的過程都封裝到了sdk中,我們可以不做過多的關(guān)注,但是一定要清楚其中的原理,可以發(fā)現(xiàn),下單的過程并沒有加密、解密的邏輯。文章來源地址http://www.zghlxwxcb.cn/news/detail-777693.html

到了這里,關(guān)于第五節(jié)、項(xiàng)目支付功能實(shí)戰(zhàn)-證書獲取、微信支付集成初始化配置、sdk統(tǒng)一下單、api安全源碼解讀的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 微信小程序第五節(jié)——登錄那些事兒(超詳細(xì)的前后端完整流程)

    微信小程序第五節(jié)——登錄那些事兒(超詳細(xì)的前后端完整流程)

    ?? 微信小程序第一節(jié) ——自定義頂部、底部導(dǎo)航欄以及獲取膠囊體位置信息。 ?? 微信小程序第二節(jié) —— 自定義組件 ?? 微信小程序第三節(jié) —— 頁面跳轉(zhuǎn)的那些事兒 ?? 微信小程序第四節(jié)—— 網(wǎng)絡(luò)請求那些事兒 ?? 作 ? ??????? 者 :是江迪呀 ?? 本文 : 微

    2024年02月09日
    瀏覽(21)
  • Springboot----項(xiàng)目整合微信支付(獲取支付二維碼)

    Springboot----項(xiàng)目整合微信支付(獲取支付二維碼)

    個人簡介 : ??個人主頁:趙四司機(jī) ??學(xué)習(xí)方向:JAVA后端開發(fā) ??種一棵樹最好的時間是十年前,其次是現(xiàn)在! ??喜歡的話麻煩點(diǎn)點(diǎn)關(guān)注喔,你們的支持是我的最大動力。 前言 目前更新的是Springboot項(xiàng)目整合微信支付系列的文章,可以在我的主頁中找到該系列其他文章,這

    2024年02月05日
    瀏覽(18)
  • HCIA-第五節(jié)(0606)

    HCIA-第五節(jié)(0606)

    路由器的轉(zhuǎn)發(fā)原理-----當(dāng)數(shù)據(jù)包進(jìn)入路由器,路由器將基于數(shù)據(jù)包中目標(biāo)IP地址,查詢本地的路由表,如果路由器中存在記錄,則將無條件按照記錄轉(zhuǎn)發(fā)。如果路由器沒有記錄,則將直接丟棄該數(shù)據(jù)包。 路由表建立的主要目標(biāo)是為了實(shí)現(xiàn)路由協(xié)議和靜態(tài)路由選擇。 chenliqidisp

    2024年02月11日
    瀏覽(42)
  • HCIP第五節(jié)------------------------------------------ospf

    HCIP第五節(jié)------------------------------------------ospf

    運(yùn)行距離矢量路由協(xié)議的路由器周期性地泛洪自己的路由表。通過路由的交互,每臺路由器都從相鄰的路由器學(xué)習(xí)到路由,并且加載進(jìn)自己的路由表中,然后再通告給其他相鄰路由器。 對于網(wǎng)絡(luò)中的所有路由器而言,路由器并不清楚網(wǎng)絡(luò)的拓?fù)?,只是簡單的知道要去往某個目

    2024年02月12日
    瀏覽(45)
  • Matlab繪圖(第五節(jié)-三維曲面)

    Matlab繪圖(第五節(jié)-三維曲面)

    具體講述了三維曲面繪圖方法等。 此時所有點(diǎn)坐標(biāo)可以表示為: 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就是該平面內(nèi)的網(wǎng)格坐標(biāo)矩陣。 (1)利用矩陣運(yùn)算生成 (2)利用meshgrid函數(shù)生成 [X,Y]=meshgrid(x,y); 其中,

    2023年04月14日
    瀏覽(23)
  • Verilog 學(xué)習(xí)第五節(jié)(串口發(fā)送部分)

    Verilog 學(xué)習(xí)第五節(jié)(串口發(fā)送部分)

    1:串口通信模塊設(shè)計(jì)的目的是用來發(fā)送數(shù)據(jù)的,因此需要有一個數(shù)據(jù)輸入端口 2:串口通信,支持不同的波特率,所以需要一個 波特率設(shè)置端口 3:串口通信的本質(zhì)就是將8位并行數(shù)據(jù)通過一根信號線,在不同的時刻傳輸并行數(shù)據(jù)的不同位,通過多個時刻,最終將8位并行數(shù)據(jù)

    2023年04月26日
    瀏覽(28)
  • 【數(shù)據(jù)結(jié)構(gòu)初階】第五節(jié).棧的詳講

    【數(shù)據(jù)結(jié)構(gòu)初階】第五節(jié).棧的詳講

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 文章目錄 前言 一、棧的基本認(rèn)識 二、棧模擬實(shí)現(xiàn):? 三、棧的實(shí)戰(zhàn)演練 3.1 有效的括號 3.2 逆波蘭表達(dá)式 3.3?棧的壓入、彈出序列 總結(jié) 上一節(jié)內(nèi)容我們學(xué)習(xí)了鏈表的有關(guān)內(nèi)容,今天我們將進(jìn)行棧的學(xué)習(xí)

    2023年04月23日
    瀏覽(30)
  • 【Git 入門教程】第五節(jié)、Git遠(yuǎn)程倉庫

    【Git 入門教程】第五節(jié)、Git遠(yuǎn)程倉庫

    Git是一種分布式版本控制系統(tǒng),它允許開發(fā)者在不同計(jì)算機(jī)之間協(xié)作并共享代碼。在本文中,我們將介紹如何以Git為基礎(chǔ)進(jìn)行遠(yuǎn)程協(xié)作。其中包括克隆倉庫、推送代碼、拉取代碼等操作。 要協(xié)作開發(fā)一個Git項(xiàng)目,需要從服務(wù)器上獲取該項(xiàng)目的副本。 運(yùn)行以下命令來克隆Git倉

    2024年02月01日
    瀏覽(22)
  • 【測試開發(fā)】第五節(jié).測試——自動化測試(Selenium工具)

    【測試開發(fā)】第五節(jié).測試——自動化測試(Selenium工具)

    作者簡介:大家好,我是未央; 博客首頁:未央.303 系列專欄:Java測試開發(fā) 每日一句: 人的一生,可以有所作為的時機(jī)只有一次,那就是現(xiàn)在?。?! 前言 一、自動化測試的概念以及分類 二、Selenium—web自動化測試工具 2.1?自動化測試的一些前置工作 2.2 第一個自動化實(shí)例

    2024年02月04日
    瀏覽(31)
  • 第五節(jié) zookeeper集群與分布式鎖_2

    第五節(jié) zookeeper集群與分布式鎖_2

    1)要介紹分布式鎖,首先要提到與分布式鎖相對應(yīng)的是線程鎖。 線程鎖 :主要用來給方法、代碼塊加鎖。當(dāng)某個方法或代碼使用鎖,在同一時刻僅有一個線程執(zhí)行該方法或該代碼段。 線程鎖只在同一JVM中有效果,因?yàn)榫€程鎖的實(shí)現(xiàn)在根本上是依靠線程之間共享內(nèi)存實(shí)現(xiàn)的,

    2024年02月19日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包