温馨提示
  • 欢迎您光临共享屋素材网,本站所有资源均来自网络或用户自主上传,本站所有素材仅交流学习用途,请勿商用。
  • 微信公众号开发——消息体加解密

    上篇文章中,我们提到微信消息加解密方式有三种,分别是明文模式、兼容模式和安全模式,选择兼容模式和安全模式,需要在公众号后台配置消息加解密秘钥EncodingAESKey。这篇文章我们来具体说一说在安全模式下微信消息加解密过程。

    当用户向公众号发送消息,微信公众账号将会在URL中带上signature、timestamp、nonce、openid、encrypt_type、msg_signature等参数发送到用户服务器,例如:

    http://wechat.acier.cn/index.php/Home/Index/index?signature=4fa4a9b8f704650c8b4b7b9b3ed840730fe7a6e5&timestamp=1556418922&nonce=716667816&openid=ou7rj1bzsmvE8SdHhVG0v6bt5m-M&encrypt_type=aes&msg_signature=f7c0ad5059052243822c2916c7aa0e978472f97e

    encrypt_type:加密类型。没有该参数或参数为raw时,表示不加密。参数为aes时,表示aes加密。

    msg_signature:对消息体的签名。

    同时推送如下XML消息,即一个已加密的消息:

    <xml>
        <ToUserName><![CDATA[gh_a1535e2cabb5]]></ToUserName>
        <Encrypt><![CDATA[jAU5g+GnBRz7bgWBonVMdibqGwOntnh+s4MXGWVB3jzMUxvkZ1LKOx6XaHEguUGNZLIYBGU4vWFWQ0vsxuJEEd14IcUN1yuUFSQDUE76BldOeTH8dzZ6lUJwWAWCvAfy/YpuNFibR06R7/jnH97WZVa8/kHgFhw6n08SNeEh6v+EzjlNZWSvNTMkbkZZOohpsCEqmvpzjmCC/kwgnZIm2sATDaZIEHZpXcLgpMCBwk3y+NNyIjDzJThXov5hYGIafTjRjYHYolLh+LIXFR9FICu8Qbo2ax+mfdWXeC0bpVWikZk4cIn2j0uRih5rAuoqKOUOhDVvy2XbDEJpslom0z9IcQVxFhn+DlRc0UkhnmAVRoSP8ZTCnZrH4G2QKx5eTP9e3RiVeK4HUR4Gqd6f9H8tYsbuITt34gCEiZxaxkY=]]></Encrypt>
    </xml>

    在服务器PHP代码中,我们需要获取到timestamp、nonce、encrypt_type和msg_signature,这些参数将用于对消息的加解密。

    程序收到微信服务器发送过来的消息后,将进行解密。对AES对称加解密的算法,微信提供了示例代码,点此下载。这里,我将下载的示例代码放在新建的WeChat目录下,并将WeChat目录放进thinkphp的Vender目录里面,然后调用进行解密,解密之后,根据业务流程,要回复给微信服务器一个消息,这时又需要对将要回复的消息进行加密,然后发送给微信服务器。具体流程代码如下:

    class IndexController extends ComController
    {
        //入口
        public function index()
        {
            define("TOKEN", "acier");
            define("AppID", "wx4abf8a686084d2fd");
            define("EncodingAESKey", "cMhGxj3Bq1Y9vcG93ef1pCWH4AUh2E3zXpLNHiF74CI");
    //        $this -> traceHttp();
            $this->logger(' http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].(empty($_SERVER['QUERY_STRING'])?"":("?".$_SERVER['QUERY_STRING'])));
            if (!isset($_GET['echostr'])) {
                $this->responseMsg();
            }else{
                $this->valid();
            }
        }
    
        //验证签名
        public function valid()
        {
            $echoStr = $_GET["echostr"];
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
            $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr);
            $tmpStr = implode($tmpArr);
            $tmpStr = sha1($tmpStr);
            if($tmpStr == $signature){
                echo $echoStr;
                exit;
            }
        }
    
        //响应消息
        public function responseMsg()
        {
            $timestamp  = $_GET['timestamp'];
            $nonce = $_GET['nonce'];
            $msg_signature  = $_GET['msg_signature'];
            $encrypt_type = (isset($_GET['encrypt_type']) && ($_GET['encrypt_type'] == 'aes')) ? "aes" : "raw";
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    //        $postStr = file_get_contents("php://input");   //如果是PHP7,则使用本行,注释上面一行
            $this->logger(" postStr \r\n".$postStr);
            if (!empty($postStr)){
                //解密
                if ($encrypt_type == 'aes'){
                    Vendor('WeChat.wxBizMsgCrypt');
                    $pc = new \WXBizMsgCrypt(TOKEN, EncodingAESKey, AppID);
                    $decryptMsg = "";  //解密后的明文
                    $errCode = $pc->decryptMsg($msg_signature, $timestamp, $nonce, $postStr, $decryptMsg);
                    $postStr = $decryptMsg;
                }
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $RX_TYPE = trim($postObj->MsgType);
    
                //消息类型分离
                switch ($RX_TYPE)
                {
                    case "event":
                        $result = $this->receiveEvent($postObj);
                        break;
                    case "text":
                        if (strstr($postObj->Content, "第三方")){
                            $result = $this->relayPart3("http://discuz.comli.com/test.php".'?'.$_SERVER['QUERY_STRING'], $postStr);
                        }else{
                            $result = $this->receiveText($postObj);
                        }
                        break;
                    case "image":
                        $result = $this->receiveImage($postObj);
                        break;
                    case "location":
                        $result = $this->receiveLocation($postObj);
                        break;
                    case "voice":
                        $result = $this->receiveVoice($postObj);
                        break;
                    case "video":
                        $result = $this->receiveVideo($postObj);
                        break;
                    case "link":
                        $result = $this->receiveLink($postObj);
                        break;
                    default:
                        $result = "unknown msg type: ".$RX_TYPE;
                        break;
                }
                //加密
                if ($encrypt_type == 'aes'){
                    $encryptMsg = ''; //加密后的密文
                    $errCode = $pc->encryptMsg($result, $timestamp, $nonce, $encryptMsg);
                    $result = $encryptMsg;
                }
                echo $result;
            }else {
                echo "";
                exit;
            }
        }
    
        //日志记录
        private function logger($log_content)
        {
            if(isset($_SERVER['HTTP_APPNAME'])){   //SAE
                sae_set_display_errors(false);
                sae_debug($log_content);
                sae_set_display_errors(true);
            }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL
                $max_size = 500000;
                $log_filename = "log.xml";
                if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
                file_put_contents($log_filename, date('Y-m-d H:i:s').$log_content."\r\n", FILE_APPEND);
            }
        }
    }
    

    以上就是对消息体加解密的演示流程。

    登录开启无限免费下载