IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 微信第三方平台授权获取component_verify_ticket加解密(laravel+php7) -> 正文阅读

[PHP知识库]微信第三方平台授权获取component_verify_ticket加解密(laravel+php7)

一、获取component_verify_ticket密文

微信第三方平台在创建审核通过后,第一步就是获取component_verify_ticket。出于安全考虑,微信服务器每隔10分钟会向你的服务器消息接收地址推送一次component_verify_ticket加密数据。该加密数据分为两部分接收,在laravel中,需要使用$request->all()接收解密参数(json字符串),file_get_contents(‘php://input’)接收加密xml字符串。获取这两部分数据后,我们就可以开始解密了。

二、解密component_verify_ticket密文

微信第三方平台官方平台已给出了加解密的demo,但版本太旧,加解密函数在php7中已弃用,其demo(仅支持php7以下)并不能,比较头大。只能结合demo中的加解密算法,重写个支持php7以上的demo(包含加密),其中ErrorCode因项目中不需要,未加入,有需要的可以对照官方demo自行添加。全部代码现分享出来,欢迎吐槽!

<?php

namespace App\Services\WeiXinXmlService;

class WeiXinXmlService
{
    private $token;
    private $encodingAesKey;
    private $appId;
    private $key;

    public function __construct()
    {
        $this->token = 'dup';
        $this->encodingAesKey = 'daeskeyaeskeyaeskeyaeskeyaeskeyaeskeyaeskey';
        $this->appId = 'third_app_id';
        $this->key = base64_decode($this->encodingAesKey . '=');
    }

    //xml格式化
    private function xmlFormat($xml)
    {
        $xmlTree = new \DOMDocument();
        $xmlTree->loadXML($xml);
        $encrypt = trim($xmlTree->getElementsByTagName('Encrypt')->item(0)->nodeValue);
        $format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
        return sprintf($format, $encrypt);
    }

    //xml提取
    private function xmlExtract($xmlText)
    {
        try {
            $xml = new \DOMDocument();
            $xml->loadXML($xmlText);
            return trim($xml->getElementsByTagName('Encrypt')->item(0)->nodeValue);
        } catch (\Exception $e) {
            return false;
        }
    }

    //xml生成
    private function xmlGenerate($encrypt, $signature, $timestamp, $nonce)
    {
        $format = "<xml><Encrypt><![CDATA[%s]]></Encrypt><MsgSignature><![CDATA[%s]]></MsgSignature><TimeStamp>%s</TimeStamp><Nonce><![CDATA[%s]]></Nonce></xml>";
        return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
    }

    //获取随机16位字符串
    private function getRandomStr()
    {
        $str = "";
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol) - 1;
        for ($i = 0; $i < 16; $i++) {
            $str .= $strPol[mt_rand(0, $max)];
        }
        return $str;
    }

    //SHA1算法
    private function getSHA1($token, $timestamp, $nonce, $encryptMsg)
    {
        try {
            $array = array($encryptMsg, $token, $timestamp, $nonce);
            sort($array, SORT_STRING);
            $str = implode($array);
            return sha1($str);
        } catch (\Exception $e) {
            return false;
        }
    }

    //解密文本
    private function decodeText($text)
    {
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }
        return substr($text, 0, (strlen($text) - $pad));
    }

    //加密文本
    private function encodeText($text)
    {
        $blockSize = 32;
        $textLength = strlen($text);
        //计算需要填充的位数
        $amountToPad = $blockSize - ($textLength % $blockSize);
        if ($amountToPad == 0) {
            $amountToPad = $blockSize;
        }
        //获得补位所用的字符
        $padChr = chr($amountToPad);
        $tmp = "";
        for ($index = 0; $index < $amountToPad; $index++) {
            $tmp .= $padChr;
        }
        return $text . $tmp;
    }

    //解密字符串
    private function decryptString($encrypted, $appId)
    {
        try {
            //使用BASE64对需要解密的字符串进行解码
            $ciphertextDec = base64_decode($encrypted);
            $iv = substr($this->key, 0, 16);
            $decrypted = openssl_decrypt($ciphertextDec, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
        } catch (\Exception $e) {
            return false;
        }
        try {
            //去除补位字符
            $result = $this->decodeText($decrypted);
            //去除16位随机字符串,网络字节序和AppId
            if (strlen($result) < 16)
                return '';
            $content = substr($result, 16, strlen($result));
            $lenList = unpack('N', substr($content, 0, 4));
            $xmlLen = $lenList[1];
            $xmlContent = substr($content, 4, $xmlLen);
            $fromAppId = substr($content, $xmlLen + 4);
        } catch (\Exception $e) {
            return false;
        }
        if ($fromAppId != $appId)
            return false;
        return $xmlContent;
    }

    //加密字符串
    public function encryptString($text, $appid)
    {
        try {
            //获得16位随机字符串,填充到明文之前
            $random = $this->getRandomStr();
            $text = $random . pack("N", strlen($text)) . $text . $appid;
            // 网络字节序
            $iv = substr($this->key, 0, 16);
            //使用自定义的填充方式对明文进行补位填充
            $text = $this->encodeText($text);
            $encrypted = openssl_encrypt($text, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
            //使用BASE64对加密后的字符串进行编码
            return base64_encode($encrypted);
        } catch (\Exception $e) {
            return false;
        }
    }

    //解密消息
    private function decryptMsg($msgSignature, $timestamp = null, $nonce, $postData)
    {
        if (strlen($this->encodingAesKey) != 43) {
            return false;
        }
        //提取密文
        $encrypt = $this->xmlExtract($postData);
        if (!$encrypt) {
            return false;
        }
        if ($timestamp == null) {
            $timestamp = time();
        }
        //验证安全签名
        $signature = $this->getSHA1($this->token, $timestamp, $nonce, $encrypt);
        if (!$signature) {
            return false;
        }
        if ($signature != $msgSignature) {
            return false;
        }
        return $this->decryptString($encrypt, $this->appId);
    }

    //加密消息
    private function encryptMsg($replyMsg, $timeStamp, $nonce)
    {
        //加密
        $encrypt = $this->encryptString($replyMsg, $this->appId);
        if (!$encrypt) {
            return false;
        }
        if ($timeStamp == null) {
            $timeStamp = time();
        }
        //生成安全签名
        $signature = $this->getSHA1($this->token, $timeStamp, $nonce, $encrypt);
        if (!$signature) {
            return false;
        }
        //生成发送的xml
        return $this->xmlGenerate($encrypt, $signature, $timeStamp, $nonce);
    }

    //解密消息示例
    public function aesDecode()
    {
        $encryptMsg = '<xml>
	<Encrypt>
		<![CDATA[zThwtRtKUf7GXFmbme724p9xKhxS+VwJJS+JvITuO1z6nCew4tGCvfFYxrIJmnRQF27Cra/mIWspUHNIbBoUJC8ueggAwbF5GCJZMCtZk/v2SspyVzaRExYLzciYi3SjI9JrBSf/rv5igZ8+xIMcS+/ssRYwWXmzYB4KXnIgStYRDbxAQFwWBtNSWQMyqgVhR605JhOl/7sfPj/uHrMv9MvTE/TBeMO3b24+ZHVHaznHv1HzalkpeBViL8t+cEHbHbiGJDwNUG6e7Nd+NTqHM8cs1ENg4cjdem+rXqVV8M2g1xIagfn2DOVJVOc37dP/FpcWG450fiPW7LpJ89vJehQTV6SJNQb3GkJDFW8ECkBph0mqfMxIO3F9OKmna7zJ]]>
	</Encrypt>
	<MsgSignature>
		<![CDATA[82b8e04a5c5a908ff4c228d97344d96e6bbd017c]]>
	</MsgSignature>
	<TimeStamp>1626140909</TimeStamp>
	<Nonce>
		<![CDATA[987390923]]>
	</Nonce>
</xml>';
        $timeStamp = '1626140909';
        $nonce = '987390923';
        $msgSign = '82b8e04a5c5a908ff4c228d97344d96e6bbd017c';
        $fromXml = $this->xmlFormat($encryptMsg);
        return $this->decryptMsg($msgSign, $timeStamp, $nonce, $fromXml);
    }

    //加密消息示例
    public function aesEncode()
    {
        $timeStamp = '1626140909';
        $nonce = '987390923';
        $text = '<xml>
	<AppId>
		<![CDATA[third_app_id]]>
	</AppId>
	<CreateTime>
	    1626140909
	</CreateTime>
	<InfoType>
		<![CDATA[component_verify_ticket]]>
	</InfoType>
	<ComponentVerifyTicket>
		<![CDATA[ticket@@@ticket]]>
	</ComponentVerifyTicket>
</xml>';
        return $this->encryptMsg($text, $timeStamp, $nonce);
    }
}
  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 10:41:11  更:2021-07-14 10:41:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 0:31:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码