天天看点

字节跳动小程序支付接入躺过的坑

字节跳动小程序支付接入

  • 躺过的坑
    • 流程
    • 签名
    • 支付宝配置问题
    • 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));
    }
           

版权声明:本文为博主原创文章,未经博主允许不得转载。

继续阅读