平安信用卡获取落地页接口demo(PHP版)

11 篇文章 0 订阅

重点在于aes加密规则,还有加密data和sign使用的secret和aesKey不要取错了。
我也是试了好多种加密方式才得出结果,现在分享给大家。

说明一下,我用的PHP版本是PHP7.3.4 ,Laravel5.7

先上平安银行提供的 java demo:

public class demo {
	
	/**
	 * 链接拼接
	 * @param initDTO
	 * @return
	 */
	public static String getUrl(InitailFormDTO initDTO){
		//sign加密KEY
		String secret="Ued234fKsd3*45fLNs3-45dfk57s";
		//AES加密KEY
		String aesKey="BWTAws7fQgOJlgLFK-xIhA..";
		String url="";
		//data值 获取
		String data=paramData(initDTO,aesKey);
		if (isNullOrBlank(data)) {
			return "ERROR.";
		}else{
			System.out.println("data最终结果:"+data);
		}
		//sign值 获取
		String sign=paramSign(initDTO,secret);
		if (isNullOrBlank(sign)) {
			return "ERROR.";
		}else{
			System.out.println("验签最终结果:"+sign);
		}
		//生成最终URl(注意测试环境和生产环境 请求不同)
		url= "https://pacesapplystg.pingan.com/ca/applyIndex?"+"data=" + data + "&sign=" + sign;
		return url;
	}
	
	/**
	 * AES  获取data值
	 * (key值顺序不一致,可能会导致加密结果不一致。可以收)
	 * @param initDTO
	 * @param aesKey
	 * @return
	 */
	public static String paramData(InitailFormDTO initDTO,String aesKey){
		//生成jason格式字段    直接使用gson,可能会更好
		String jsonParam = JSONObject.toJSONString(getJasonMap(initDTO));//字段转Json 
		System.out.println("json格式结果:"+jsonParam);
		String result = encrypt(jsonParam, aesKey);//AES加密
		System.out.println("AES加密后结果:"+result);
		if (!isNullOrBlank(result)) {  //在最前面拼上9位的SCC和20位的mt参数值(mt参数如果不足20位用0补足),形成最终的密文数据。	
			if (isNullOrBlank(initDTO.getMt())) {
				return initDTO.getScc() + "00000000000000000000" + result;
			} else {
				return initDTO.getScc() + StringUtils.leftPad(initDTO.getMt(), 20, '0') + result;
			}
		}else{
			return null;
		}
	}
	
	/**
	 * HmacSHA256验签  获取sign值
	 * @param initDTO
	 * @param aesKey
	 * @return
	 */
	public static String paramSign(InitailFormDTO initDTO,String secret){
		String generateSign = null;
		try {
			Field[] fields = InitailFormDTO.class.getDeclaredFields();
			List<String> list = new ArrayList<String>();
			if (fields != null) {
				for (Field a : fields) {
					String name = a.getName();
						Method m = InitailFormDTO.class.getMethod("get" + name.substring(0, 1).toUpperCase() + name.substring(1));
						if (!isNullOrBlank((String) m.invoke(initDTO))) {
							list.add(name);
						}
				}
				if (list.size() > 0) {
					Collections.sort(list);//将所有参数按key的ASCII码从小到大排序
					StringBuffer bf = new StringBuffer();
					for (String key : list) {//使用&符号拼接
						String value = (String) InitailFormDTO.class.getMethod("get" + key.substring(0, 1).toUpperCase() + key.substring(1)).invoke(initDTO);
						bf.append("&");
						bf.append(key);
						bf.append("=");
						bf.append(value);
					}
					//将最终的字符串转换成全大写,再使用HmacSHA256进行签名。
			        System.out.println("排序后拼接转大写:"+bf.substring(1).toString().toUpperCase());	
					generateSign = sign(bf.substring(1).toString().toUpperCase(),secret);
				}
			}
			return generateSign;
		} catch (Exception e) {
			return null;
		}
	}
	
	/**										
	 * AES加密	
	 * 参数使用json格式,
	 * AES加密后再对加密后的字符串进行UrlBase64编码,
	 * @param data										
	 *            需要加密的字符串										
	 * @param aesKey										
	 *            AES key										
	 * @return										
	 */
	 /**
     		* json格式结果:{"partnerSeqId":"m180320106300000201804191255555271111","scc":"920000999","templateNo":"s180419Oot","mt":"123456789","ccp":"1a2a3a9","versionNo":"R10310","onlineSQFlag":"N","cardCatenaNo":"01a02a04","channel":"WXHZF"}
          * AES加密后结果:Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.
               **/
	public static String encrypt(String data, String aesKey) {										
	   try {										
		if (isNullOrBlank(data) || isNullOrBlank(aesKey)) {									
			System.out.println("AESUtil.encrypt data or aesKey is null.");								
			return null;								
		}

		byte[] aesByte = UrlBase64.decode(aesKey);									
		SecretKeySpec skeySpec = new SecretKeySpec(aesByte, "AES");									
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");									
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec);									
		byte[] encryptedByte = cipher.doFinal(data.getBytes("utf-8"));									
		return new String(UrlBase64.encode(encryptedByte));									
	     } catch (Exception e) {										
	    	 System.out.println("AESUtil.encrypt exception."+e);									
		return null;									
	   }										
	}	


    public static String desEncrypt(String data, String key, String ivString)
    {
        byte[] iv = null;
        try {
             iv = ivString.getBytes();
             byte[] encryp = Base64.getDecoder().decode(data);
             Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
             SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
             IvParameterSpec ivSpec = new IvParameterSpec(iv);
             cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
             byte[] original = cipher.doFinal(encryp);
             return new String(original);
         } catch (Exception e) {
            e.printStackTrace();
         }
         return null;
     }

	/**												
	 * HmacSHA256加密	
	 * 请确保key值顺序排列											
	 * @param value												
	 *            需要加密的字符串												
	 * @param secret												
	 *            HmacSHA256 key												
	 * @return												
	 */												
	public static String sign(String value,String secret) {												
		try {											
			Mac sha256_HMAC = Mac.getInstance("HmacSHA256");										
			SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
			sha256_HMAC.init(secret_key);										
			String hash =new String(UrlBase64.encode(sha256_HMAC.doFinal(value.getBytes("utf-8"))));										
			return hash;										
		} catch (Exception e) {											
			System.out.println("Failed to generate the sign."+ e);										
			return null;										
		}											
	}	
	
	public static boolean isNullOrBlank(String str) {
		if (str == null || str.equals("") || str.equals("null")) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 判断每个字段是否为空
     * 返回去除value的key值
	 * @param obj
	 * @return
	 */
	private static Map<String,String> getJasonMap(Object obj){
		Field[] field = obj.getClass().getDeclaredFields();
		Map<String,String> returnMap=new HashMap<String,String>();
		try {
			for (int j = 0; j < field.length; j++) {
				String name = field[j].getName();
				// 过滤serialVersionUID字段
				if ("serialVersionUID".equals(name)) {
					continue;
				}
				String name1 = name.substring(0, 1).toUpperCase() + name.substring(1);
				Method m = obj.getClass().getMethod("get" + name1);
				String value = (String) m.invoke(obj);
				if (!isNullOrBlank(value)) {
					returnMap.put(name, value);
				}
			}
		} catch (Exception e) {
			 System.out.println(e);
		}
		return returnMap; 
   }	
	
	public static void main(String[] args) {
		String url="";
		InitailFormDTO initDTO=new InitailFormDTO();
		StringBuilder random = new StringBuilder();
		for (int i = 0; i < 40; i++) {
			int nextInt = new Random().nextInt(10);
			System.out.println(nextInt);
			random.append(nextInt);
		}
		 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		 String data = simpleDateFormat.format(new Date());
		/***************************参数赋值,请和业务确定*********************************************/
		/*11位商户号+ 时间(yyyyMMddHHmmssSSS) + 4位随机数据数字。
		 * 商户号业务分配
		 * 时间可以自己用工具类生成
		 * 随机数可自己定义
		 *
		 *流水号只能点一次。
		 *流水号只能用一次
		 *流水号只能开一次。
		 */
		initDTO.setPartnerSeqId("m180320106300000"+data+ random.toString());
		
		
		initDTO.setScc("920000999");// 业务分配
		initDTO.setTemplateNo("s180419Oot"); // 业务分配
		initDTO.setMt("123456789"); // 咨询业务
		initDTO.setCcp("1a2a3a9"); // 咨询业务
		initDTO.setVersionNo("R10310"); // 业务分配
		initDTO.setOnlineSQFlag("N"); // 定值 
		initDTO.setCardCatenaNo("01a02a04"); // 咨询业务
		initDTO.setChannel("WXHZF"); // 定值
		/***************************中文记得转码UTF-8*************************************************/
		System.out.println("需要加密的入参:"+initDTO);
		url=getUrl(initDTO);
		System.out.println( "最终生成测试环境url:" + url);
		
		
		/**
		 * 结果:
		 * 需要加密的入参:InitailFormDTO [versionNo=R10310, scc=920000999, onlineSQFlag=N, channel=WXHZF, cardCatenaNo=01a02a04, ccp=1a2a3a9, cf=null, cc=null, salesName=null, salesCode=null, salesmanPhoneNO=null, bt1=null, bt2=null, bt3=null, bt4=null, bt5=null, bt6=null, bt7=null, bt8=null, bt9=null, bt10=null, mt=123456789, recommendChineseName=null, recommendPhone=null, isDisplayRecommend=null, isDisplaySales=null, onePlusOneWB=null, onePlusOneYL=null, url=null, templateNo=s180419Oot, partnerSeqId=m180320106300000201804191255555271111, idCardStatus=null, partnerInfoIndex=null, salesmanType=null, hasZiGeSaleMan=null]
         * json格式结果:{"partnerSeqId":"m180320106300000201804191255555271111","scc":"920000999","templateNo":"s180419Oot","mt":"123456789","ccp":"1a2a3a9","versionNo":"R10310","onlineSQFlag":"N","cardCatenaNo":"01a02a04","channel":"WXHZF"}
         * AES加密后结果:Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.
         * data最终结果:92000099900000000000123456789Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.
         * 排序后拼接转大写:CARDCATENANO=01A02A04&CCP=1A2A3A9&CHANNEL=WXHZF&MT=123456789&ONLINESQFLAG=N&PARTNERSEQID=M180320106300000201804191255555271111&SCC=920000999&TEMPLATENO=S180419OOT&VERSIONNO=R10310
         * 验签最终结果:iMMUARHZgiCRSzKOfp0dJ0-pbxCbH7eoPmB3eKj2nGs.
         * 最终生成测试环境url:https://pacesapplystg.pingan.com/ca/applyIndex?data=92000099900000000000123456789Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.&sign=iMMUARHZgiCRSzKOfp0dJ0-pbxCbH7eoPmB3eKj2nGs.
		 */
		
	}
}

demo最后试加密过程的打印结果,按照打印结果对照执行结果是否一致

<?php

class Service
{
    protected $domain = 'https://pacesapplystg.pingan.com/';
    public function __construct () {
        parent::__construct();
    }

	//入口方法
    public function getBankUrl($params = [],$serial_number = '')
    {
        $requestData = '{"partnerSeqId":"m180320106300000201804191255555271111","scc":"920000999","templateNo":"s180419Oot","mt":"123456789","ccp":"1a2a3a9","versionNo":"R10310","onlineSQFlag":"N","cardCatenaNo":"01a02a04","channel":"WXHZF"}';
        $requestData = json_decode($requestData, true);
        $SECRET = 'Ued234fKsd3*45fLNs3-45dfk57s';
        $AESKEY = 'BWTAws7fQgOJlgLFK-xIhA..';
        $data = $this->paramData($requestData, $AESKEY);
        dump("data最终结果:".$data);
        $sign = $this->paramSign($requestData, $SECRET);
        dump("验签最终结果:".$sign);  
        return $this->domain."ca/applyIndex?data=" . $data  ."&sign=" . $sign;
    }

    public function getUrlParams($param)
    {
        ksort($param);
        $str = '';
        //循环拼接参数
        foreach ($param as $key => $value) {
            $str .= $key . "=" . urlencode($value) . "&";
        }
        $str = substr($str, 0, strlen($str) - 1);
        return $str;
    }

    public function paramData($param = [], $aesKey)
    {
        $jsonParam = json_encode($param);
        dump("json格式结果:".$jsonParam);
        $result = $this->ssl_encrypt($jsonParam, $aesKey);
        dump('AES加密后结果:'.$result);
        if(!$result) {
            return false;
        }
        $data_per = $param['scc'];
        if(isset($param['mt'])){
            $num_len = strlen($param['mt']);
            for($i = 0; $i <20-$num_len; $i++){
                $data_per = $data_per . '0';
            }
            $data_per .= $param['mt'];
        } else{
            for($i = 0; $i <20; $i++){
                $data_per = $data_per . '0';
            }
        }
        $result = $data_per.$result;
        return $result;
    }

    /**
     * 获取sign(HmacSHA256验签)
     * @param array $params
     * @param string $secret
     * @return string
     */
    public function paramSign($params = [], $secret = '')
    {
        ksort($params);
        $str = '';
        foreach ($params as $key => $value) {
            $str .= $key . "=" . urlencode($value) . "&";
        }
        $str = substr($str, 0, strlen($str) - 1);
        //字符串转大写
        $str = strtoupper($str);
        //HMAC-SHA256加密
        $sign = hash_hmac('sha256', $str, $secret, true);
        //参数编码
        $sign = $this->base64UrlEncode($sign);
        return $sign;
    }

    /**
     * PHP7 AES 加密
     * @param $str
     * @param $aesKey
     * @return mixed
     */
    public function ssl_encrypt($str, $aesKey)
    {
        $data = openssl_encrypt($str, 'aes-128-ecb', $this->base64UrlDecode($aesKey), OPENSSL_RAW_DATA);
        return $this->base64UrlEncode($data);
    }

    /**
     * 获取sign(HmacSHA256验签)
     * @param $data
     * @param $secret
     * @return string|string[]
     */
    public function sign($data, $secret)
    {
        ksort($data);
        $str = '';
        foreach ($data as $key => $value) {
            //拼接参数
            $str .= $key . "=" . urlencode($value) . "&";
        }
        //去除最后一个字符
        $str = substr($str, 0, strlen($str) - 1);
        //字符串转大写
        $str = strtoupper($str);
        //HMAC-SHA256加密
        $sign = hash_hmac('sha256', $str, $secret, true);
        $sign = $this->base64UrlEncode($sign);
        return $sign;
    }

    public function base64UrlEncode($str)
    {
        $data = base64_encode($str);
        $data = str_replace(array('+', '/', '='), array('-', '_', '.'), $data);
        return $data;
    }

    public function base64UrlDecode($str)
    {
        $data = str_replace( array('-', '_', '.'), array('+', '/', '='),$str);
        return base64_decode($data);
    }
}

控制打印结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值