银联在线支付对接流程以及签名算法

Posted SuperAvalon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了银联在线支付对接流程以及签名算法相关的知识,希望对你有一定的参考价值。

银联在线支付

简介

银联在线支付支持PC网关、手机SDK、WAP网关、云闪付等多种支付场景,其中云闪付产品可以完美支持ApplePay、Samsung Pay、Huawei Pay等市面上常见的手机厂商推出的支付品牌,对接银联在线支付,可弥补因无微信客户端和支付宝客户端所造成的用户流失,还可以做形式多样的支付优惠活动,银联可通过对商户号交易控制实现其立减、满减等支付优惠活动。

支付流程

根据开发文档组织支付报文,发起网关支付请求。APP支付,需要curl请求支付网关(appTransReq.do),获取到tn码,然后app通过tn码发起支付请求。PC、WAP网关支付,则直接将支付报文通过表单POST提交至银联支付网关(frontTransReq.do)。

签名机制

银联在线支付,商户端在调用支付网关、退款网关、支付查询网关、退款查询网关等业务需要使用OpenSSL对报文进行非对称加密,加密证书类型为RSA,加密算法为SHA-1。同样,商户端对来自银联发来的数据报文,也要同样的使用银联提供的公钥文件对其签名做验证操作;

在线开发文档

https://open.unionpay.com/ajweb/product

证书下载、导出流程

https://open.unionpay.com/ajweb/help/file/techFile?cateLog=agreement

银联在线支付签名验签算法

/**
 * 银联在线支付demo
 * 使用OpenSSL进行非对称加密、验签
 * @author think2017@gmail.com
 */
class chinapayPayment

    
    
    public function __construct()
    
        
    
    
    
    /**
     **@desc 获取支付请求报文
     **/
    public function ransReqParams()
    
        //Todo...
    
    
    
    /**
     **@desc 退款申请
     **/
    public function doRefund()
    
        //Todo...
    
    
    
    /**
     **@desc 支付查询
     **/
    public function doQuery()
    
        //Todo...
    
    
    
    /**
     **@desc 退款查询
     **/
    public function doRefundQuery()
    
        //Todo...
    
    
    
    /**
    * 使用商户私钥文件对报文进行签名
    */
    public function signature($postPrams)
    
        ksort($postPrams);

        $strInfo = '';
        foreach ($postPrams as $key=>$val) 
            if($strInfo)
                $strInfo .= "&".$key."=".$val;
            else
                $strInfo = $key."=".$val;
            
        
        
        $retval = $this->readPrivateKeyData();
        
        if ($retval['code'] != 200) 
           return false;
        

        $sha1x16 = sha1($strInfo, FALSE);
        if (openssl_sign($sha1x16, $signature, $retval['privateKey'], OPENSSL_ALGO_SHA1)) 
            $signatureBase64 = base64_encode($signature);
        

        return $signatureBase64 ? $signatureBase64 : false;
    
    
    
    /**
    * 使用银行公钥文件进行验签
    */
    public function verfiySign($requestData)
    
        $retval = $this->readPublicKeyData();
        
        if ($retval['code'] != 200) 
           return false;
        
        
        $isSuccess = false;
        
        if( $retval['certId'] == $requestData['certId'] )
            $signature = $requestData['signature'];
            unset($requestData['signature']);
            $sRequest = $this->coverParamsToString($requestData);
            $sha1x16 = sha1($sRequest, false);
            $isSuccess = openssl_verify($sha1x16, base64_decode($signature), $retval['publicKey'], OPENSSL_ALGO_SHA1);
        
        
        return $isSuccess;
    
    

    /**
     * 读取商户私钥,私钥证书文件后缀为.pfx
    **/
    private function readPrivateKeyData()
    
        $pkcs12 = file_get_contents($this->privateKeyFile);

        if (openssl_pkcs12_read($pkcs12, $certs, $this->privatekeyPass))  
            $x509data = $certs ['cert'];
            openssl_x509_read ( $x509data );
            $certdata = openssl_x509_parse ( $x509data );
            return ['code' => 200, 'certId' => $certdata['serialNumber'], 'privateKey' => $certdata['pkey']];
        
        
        return ['code' => 500, 'certId' => '', 'privateKey' => ''];
    
    
    

    /**
     * 读取银行公钥,公钥证书文件后缀为.cer
    **/
    private function readPublicKeyData()
    
        $x509data = file_get_contents($this->publicKeyFile);
        openssl_x509_read($x509data);
        $certdata = openssl_x509_parse($x509data);
        
        if ($certdata) 
            return ['code' => 200, 'certId' => $certdata['serialNumber'], 'publicKey' => $x509data];
        
        
        return ['code' => 500, 'certId' => '', 'publicKey' => ''];
    

    
    /**
     * 数组 排序后转化为字体串
     * @param array $params            
     * @return string
     */
    public function coverParamsToString($params) 
    
        $strSign = '';
        ksort($params);
        foreach($params as $key => $val)
            if($key == 'signature')
                continue;
            
            $strSign .= sprintf("%s=%s&", $key, $val);
        
        return substr($strSign, 0, strlen($strSign) - 1);
    


以上是关于银联在线支付对接流程以及签名算法的主要内容,如果未能解决你的问题,请参考以下文章

经典设计模式之策略模式如何重构聚合支付平台,对接支付宝,微信,银联支付

app测试(兼容性测试)

第三方支付-银联云闪付开发教程

炼金术: 怎样做好1个业务流程的接口对接

BTC比特币币圈金融资金盘系统定制支付通道申请第三方支付接口对接搭建 支付宝微信扫码网关网银银联快捷支付

ECSHOP 银联电子支付(ChinaPay)插件 掉用JAVA签名