天天看點

位元組跳動小程式支付接入躺過的坑

位元組跳動小程式支付接入

  • 躺過的坑
    • 流程
    • 簽名
    • 支付寶配置問題
    • java福利

躺過的坑

  • 流程
    • 小程式申請流程
    • 業務調用流程
  • 簽名
    • 請求位元組跳動接口的簽名
    • 請求預下單傳回驗簽
  • 支付寶配置問題

流程

  • 小程式申請流程
    • 位元組跳動小程式開通申請有個管道秘鑰類型選擇RSA2和RSA,不管你選擇哪個,和最後拉起的支付寶url沒關系,這裡的選擇不影響支付寶的簽名;比如這裡選擇RSA2,我支付寶簽名使用RSA是沒問題的。(申請開通支付)
      位元組跳動小程式支付接入躺過的坑
    • 位元組跳動小程式支付的商戶配置和支付寶的支付商戶配置是沒有關系的兩個東西。前者是和位元組跳動這邊的互相簽名驗簽需要的東西;後者是拉起支付寶支付的東西。不要把前者的商戶、APPID、支付secret和後者的mchid、APPID、公鑰私鑰混在一起。隻不過要在位元組跳動這邊發起支付,需要去他們平台做一個身份認證,然後幫你拉起支付而已。
      位元組跳動小程式支付接入躺過的坑
  • 業務調用流程
    • 支付業務調用流程:

      1.預下單:擷取位元組跳動的内部訂單号(服務端下單接口);

      2.調用支付寶app支付,擷取拉起支付寶支付url(支付寶app支付接口2.0);

      3.組裝前端發起參數(發起頭條支付);

簽名

  • 請求位元組跳動接口的簽名(簽名說明)
    • 1.注意參數類型,特别是涉及金額的字段(如:total_amount)機關是分,參數類型是整數;
    • 2.請求簽名類型選擇MD5,最後組裝的參數字元串string + app_secret,**中間是沒有‘&’**連接配接的;
  • 請求預下單傳回驗簽
    • 1.接口傳回參數驗簽,最後組裝的驗簽參數字元串string ,不需要app_secret;
    • 2.驗簽的算法是MD5withRSA,之前自己誤認為是先MD5然後在用RSA驗簽,其實這個是一個算法名稱;

支付寶配置問題

如果和位元組跳動的互動都沒問題,還是傳回報錯:{“errMsg”:“requestPayment:fail 4000”};

  • 那麼就要檢查支付寶url的問題了,看自己下的單能否單獨拉起支付寶;下載下傳支付寶測試app(用戶端調試工具),看看自己的配置是否有問題;
  • 如果使用支付寶測試app拉起支付報錯ALIN10146-有對應的自查方案(ALIN10146-自查方案);

java福利

  • 組裝簽名參數:
import org.apache.commons.codec.digest.DigestUtils;

//對請求參數進行組裝+key
public static String alipayLiteSign(Map<String, Object> map,String key) {

		String result = getSignCheckContent(map);
		result=result+key;
		
		String sign = DigestUtils.md5Hex(result.toString());
		log.info("alipayLiteSign: sign-content={};sign={}",result,sign);
		
		return sign;
	
	}
	
	//組裝參數
	public static String getSignCheckContent(Map<String, Object> map) {
		
		ArrayList<String> list = new ArrayList<String>();
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			
			if (entry.getKey().equals("sign")) {
				continue;
			}
			if (entry.getValue() != null && entry.getValue() != "") {
				list.add(entry.getKey() + "=" + entry.getValue() + "&");
			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		String result = sb.toString();
		result = result.substring(0, result.length()-1);
		return result;
		
	}
           
  • 數字簽名-驗簽
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;

 	/**
     * String轉公鑰PublicKey
     * @param key
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new Base64()).decode(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }
    
	//對用md5和RSA私鑰生成的數字簽名進行驗證
    public static boolean verifyWhenMd5Sign(String content, String sign, PublicKey publicKey) throws Exception {
        byte[] contentBytes = content.getBytes("utf-8");
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);
        signature.update(contentBytes);
        return signature.verify(Base64.decodeBase64(sign));
    }
           

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

繼續閱讀