ThinkPHP5微信小程序登录解密

第1步:在TP5项目application里面新建tools工具类模块,写入WeChatOpenid.php在TP5项目application里面新建tools工具类模块,写入WeChatOpenid.php
<?php
/**
 * Pasa吴
 * 2019年2月7日15:48:40
 */
namespace app\tools;

use think\Cache;
use think\Controller;
use think\config;
use think\Db;

class WeChatOpenid extends Controller
{
    //微信小程序appid
    protected $appid;
    //微信小程序secret
    protected $secret;

    /**
     * 构造方法
     * [__construct description]
     * @Pasa吴
     * @DateTime 2019-01-22T16:39:56+0800
     * @param    [type]                   $appid  [微信小程序appid]
     * @param    [type]                   $secret [微信小程序secret]
     */
    public function __construct($appid, $secret)
    {
        $this->appid  = trim($appid);
        $this->secret = trim($secret);
    }

    /**
     * 微信小程序登录解密
     * @param $code
     * @param $iv
     * @param $encryptedData
     * @return array
     */
    public function WeChatDecrypt($code, $iv, $encryptedData)
    {
        //获取session_key
        $params['appid']  = $this->appid;
        $params['secret'] = $this->secret;

        $params['js_code']    = $this->define_str_replace($code);
        $params['grant_type'] = 'authorization_code';
        $http_key             = $this->httpCurl('https://api.weixin.qq.com/sns/jscode2session', $params, 'GET');
        $session_key          = json_decode($http_key, true);
        if (!empty($session_key['session_key'])) {
            $appid = $params['appid'];
            //$encryptedData = urlencode($this->param['encryptedData']);
            //$encryptedData = urldecode($encryptedData);
            $iv      = $this->define_str_replace($iv);
            $errCode = $this->decryptData($appid, $session_key['session_key'], $encryptedData, $iv);
            if (is_numeric($errCode)) {
                return ['errCode' => $errCode, 'mes' => '小程序登录解密失败'];
            }
            return $errCode;
        } else {
            return ['errCode' => -1, 'mes' => '获取session_key失败'];
            //return '获取session_key失败!';
        }
    }

    /**
     * 微信信息解密
     * @param  string $appid 小程序id
     * @param  string $sessionKey 小程序密钥
     * @param  string $encryptedData 在小程序中获取的encryptedData
     * @param  string $iv 在小程序中获取的iv
     * @return array 解密后的数组
     */
    function decryptData($appid, $sessionKey, $encryptedData, $iv)
    {
        $OK                = 0;
        $IllegalAesKey     = -41001;
        $IllegalIv         = -41002;
        $IllegalBuffer     = -41003;
        $DecodeBase64Error = -41004;

        if (strlen($sessionKey) != 24) {
            return $IllegalAesKey;
        }
        $aesKey = base64_decode($sessionKey);

        if (strlen($iv) != 24) {
            return $IllegalIv;
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result  = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj = json_decode($result);
        if ($dataObj == NULL) {
            return $IllegalBuffer;
        }
        if ($dataObj->watermark->appid != $appid) {
            return $DecodeBase64Error;
        }
        $data = json_decode($result, true);

        return $data;
    }

    /**
     * 请求过程中因为编码原因+号变成了空格
     * 需要用下面的方法转换回来
     */
    function define_str_replace($data)
    {
        return str_replace(' ', '+', $data);
    }

    /**
     * 发送HTTP请求方法
     * @param  string $url 请求URL
     * @param  array $params 请求参数
     * @param  string $method 请求方法GET/POST
     * @return array  $data   响应数据
     */
    function httpCurl($url, $params, $method = 'POST', $header = array(), $multi = false)
    {
        date_default_timezone_set('PRC');
        $opts = array(
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER     => $header,
            CURLOPT_COOKIESESSION  => true,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_COOKIE         => session_name() . '=' . session_id(),
        );
        /* 根据请求类型设置特定参数 */
        switch (strtoupper($method)) {
            case 'GET':
                // $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                // 链接后拼接参数  &  非?
                $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                break;
            case 'POST':
                //判断是否传输文件
                $params                   = $multi ? $params : http_build_query($params);
                $opts[CURLOPT_URL]        = $url;
                $opts[CURLOPT_POST]       = 1;
                $opts[CURLOPT_POSTFIELDS] = $params;
                break;
            default:
                throw new Exception('不支持的请求方式!');
        }
        /* 初始化并执行curl请求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data  = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if ($error) throw new Exception('请求发生错误:' . $error);
        return $data;
    }
}
第2步:在任意一个控制器use刚刚写的类,new的时候传入微信小程序appid和微信小程序secret。在调用WeChatDecrypt方法传入code, iv, encryptedData即可获取用户信息
<?php
/**
 * Pasa吴
 * 2018年10月3日11:28:38
 * https://pasawu.top/
 * QQ476460973
 */

namespace app\api\controller\v1;

use app\common_ext\controller\ApiBase;

use app\tools\WeChatOpenid;

class Openid extends ApiBase
{
    public function weixinlogin()
    {
        $WeChatOpenid = new WeChatOpenid(trim(config::get("setting.appid")), trim(config::get("setting.secret")));

        $WeChatUserInfo = $WeChatOpenid->WeChatDecrypt($this->param['code'], $this->param['iv'], $this->param['encryptedData']);
        if (!empty($WeChatUserInfo['errCode'])) {
            $this->jump([$WeChatUserInfo['errCode'], $WeChatUserInfo['mes'], $this->param]);
        } else {
            $this->jump([SUCCESS, "授权登录成功", $this->res['userInfo'] = $WeChatUserInfo]);
        }
    }
}
WeChatDecrypt返回值如果errCode不为空即失败打印errCode查找报错原因

Pasa吴技术博客
请先登录后发表评论
  • latest comments
  • 总共0条评论