支付宝服务窗验证签名

<?php
/**
 * Desc 注意生成的私钥和公钥是2048位,PKCS1(PHP使用,如果是java,使用PKCS8),编码GBK,然后用支付宝的秘钥生成公钥来生成。这个网关是为了用来支付宝做notify_url的,所以支付宝必须确保验证签名正确,你的接口安全,才能让你使用开发者模式。
 * Author: xiexingqiao
 * Date: 2017/5/22
 * Time: 10:34
 */


class AliNotifyController 
{
private $config = array (
    //应用ID,您的APPID。
        'app_id' => "****",
       //商户私钥,您的原始格式私钥,一行字符串
        'merchant_private_key' => '-----BEGIN PRIVATE KEY-----
****
-----END PRIVATE KEY-----
',
            //商户应用公钥,一行字符串
        'merchant_public_key' => "***",
            //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
        'alipay_public_key' => '****',//没有-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----

            //编码格式只支持GBK。
        'charset' => "GBK",
            //支付宝网关
        'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
            //签名方式
        'sign_type'=>"RSA2"
        );
 

    /**
     * ali服务窗应用网关验证
     */
    public function actionGateway()
    {
//        $_POST['service']='alipay.service.check';
//        $_POST['sign']='ntjOmXFGJMdfdMnrTL5rEp9QG8d0lDEoGg3ZHvqemHeI8BlQoEsFbhEn0IfQT+pvfJz5RCuE+3Qh1X7I4z5iTIiGjDBstc0xeuiAmtP9TrJZuw2jUAODFB9qOwBJLNcWlKHUGTU/db/qRsJQCj8EjoJvSi9MRM/xKv/XmduS/C4=';
//        $_POST['sign_type']='RSA2';
//        $_POST['charset']='GBK';
/*        $_POST['biz_content']='<?xml version="1.0" encoding="gbk"?><XML><AppId><![CDATA['.$this->config['app_id'].']]></AppId><FromUserId></FromUserId><CreateTime><![CDATA[1406083506817]]></CreateTime><MsgType><![CDATA[event]]></MsgType><EventType><![CDATA[verifygw]]></EventType><ActionParam></ActionParam><AgreementId></AgreementId><AccountNo></AccountNo></XML>';
      */

        $sign = Yii::$app->request->post( "sign",$_POST['sign'] );
        $sign_type =  Yii::$app->request->post ( "sign_type" ,$_POST['sign_type']);
        $biz_content =  Yii::$app->request->post ( "biz_content",$_POST['biz_content'] );
        $service =  Yii::$app->request->post( "service" ,$_POST['service']);
        $charset =  Yii::$app->request->post( "charset" ,$_POST['charset']);

        if (empty ( $sign ) || empty ( $sign_type ) || empty ( $biz_content ) || empty ( $service ) || empty ( $charset )) {
          Yii::info("some parameter is empty.");
            exit ();
        }

        $sign_verify = $this->verify($_POST);//,$this->config['alipay_public_key']
        if($service == 'alipay.service.check')
        {
         // 验证签名,开通开发者模式
            if(!$sign_verify)
            {
                Yii::info('sign qianming verfiy fail.');
                $this->verifygw(false);
            }else{
                Yii::info('sign qianming verfiy success.');
                $this->verifygw(true);
            }
            return true;
        }elseif($service == 'alipay.mobile.public.message.notify'){
            // 处理收到的消息
        }

        Yii::info('exception happen');

    }

    /* 使用支付宝的公钥对支付宝来的消息进行验签 */
    private  function verify($params) {

        Yii::info(json_encode($params));
        $sign = $params['sign'];
        unset($params['sign']);
        ksort($params);

        $data = http_build_query($params);
        $AliRsaPublicKeyFilePath=Yii::getAlias('@app').'/config/alipay_public_key_sha256.pem';

        if(file_exists($AliRsaPublicKeyFilePath))
        {
            /* 读取公钥文件,PEM格式 */
            $pubKey = file_get_contents($AliRsaPublicKeyFilePath);
        }else{
            Yii::info('alipay_public_key_sha256.pem not exist,verify fail');exit;
        }
        /* 转换为openssl格式密钥 */
        $res = openssl_get_publickey($pubKey);
        if(!$res)
        {
            Yii::info('转换为openssl格式密钥失败');exit;
        }

        /* 调用openssl内置方法验签 */
        $result = (bool) openssl_verify($data, base64_decode($sign), $res);

        /* 释放资源 */
        openssl_free_key($res);

        /* 返回验签结果 */
        return $result;
    }
    private  function verifygw($is_sign_success) {

        if ($is_sign_success) {
            $response_xml = "<success>true</success><biz_content>" . $this->config ['merchant_public_key'] . "</biz_content>";

        } else { // echo $response_xml;
            $response_xml = "<success>false</success><error_code>VERIFY_FAILED</error_code><biz_content>" . $$this->config ['merchant_public_key'] . "</biz_content>";
        }
        $mysign=$this->alonersaSign($response_xml,$this->config['merchant_private_key'],$this->config['sign_type']);
        $return_xml = "<?xml version=\"1.0\" encoding=\"".$this->config['charset']."\"?><alipay><response>".$response_xml."</response><sign>".$mysign."</sign><sign_type>".$this->config['sign_type']."</sign_type></alipay>";
        Yii::info($return_xml);
        echo $return_xml;

    }
    /**
     * RSA单独签名方法,未做字符串处理,字符串处理见getSignContent()
     * @param $data 待签名字符串
     * @param $privatekey 商户私钥,根据keyfromfile来判断是读取字符串还是读取文件,false:填写私钥字符串去回车和空格 true:填写私钥文件路径
     * @param $signType 签名方式,RSA:SHA1     RSA2:SHA256
     * @param $keyfromfile 私钥获取方式,读取字符串还是读文件
     * @return string
     * @author mengyu.wh
     */
    public function alonersaSign($data,$privatekey,$signType = "RSA") {

        $res = openssl_get_privatekey($privatekey);
        if(!$res)
        {
            Yii::info('您使用的私钥格式错误,请检查RSA私钥配置');exit;
        }


        if ("RSA2" == $signType) {
            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            openssl_sign($data, $sign, $res);
        }

        $sign = base64_encode($sign);
        return $sign;

    }
}

猜你喜欢

转载自blog.csdn.net/xxq929604980/article/details/72676395