• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    PHP实现微信小程序用户授权的工具类示例

    先准备工作

    1.申请一个小程序,申请地址:传送门
    2.仔细阅读小程序的用户授权登陆官方文档: 《用户授权登陆的流程》
    3.仔细阅读微信用户数据解密的相关文档: 《用户数据解密说明文档》
    4.在小程序后台配置好相应的后端请求地址,路径是:开发---->开发设置,如图


    5.小程序如果需要做多个小程序的打通,还需要在微信开放平台绑定到开发者账号下面, 如果不需要union_id请忽略

    6.服务端准备一个用户授权的接口,假设接口链接为http://test.dev.com/user/authorization,此接口接受如下参数

    接口返回的数据如下

    {
      "errcode": 200,
      "msg": "SUCCESS",
      "data": {
        "uid": 34098,
        "unionid": "xxx",
      }
    }

    6.建表

    1)用户表,其中比较重要的字段是union_id,因为我们是有多个小程序和公众号,因此使用这个来区分唯一的用户编号

    DROP TABLE IF EXISTS `jz_wxa_user`;
    CREATE TABLE `jz_wxa_user` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
     `uid` bigint(18) DEFAULT NULL,
     `openid` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'openid',
     `user_name` varchar(100) CHARACTER SET utf8mb4 DEFAULT '',
     `nick_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '用户昵称',
     `sex` enum('0','1') CHARACTER SET utf8 DEFAULT '1' COMMENT '性别',
     `avatar` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户头像',
     `province` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '省份',
     `city` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '城市',
     `country` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '国家',
     `wx_union_id` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '公众平台的唯一id',
     `from_url` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '来源url',
     `created_at` timestamp NULL DEFAULT NULL,
     `updated_at` timestamp NULL DEFAULT NULL,
     `from_appid` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT 'wx95fc895bebd3743b' COMMENT '来源appid',
     `wx_header` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '微信头像',
     `gh_openid` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '微信公众号openid',
     `phone` varchar(30) CHARACTER SET utf8 DEFAULT '' COMMENT '手机号码',
     PRIMARY KEY (`id`),
     KEY `idx_uid_union_id` (`uid`,`wx_union_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    实现步骤

    用户授权时序图

    关键代码

    小程序端

    小程序端的获取用户信息流程

    1)调用login方法获取code
    2)调用getUserInfo方法获取用户的加密数据
    3)调用后端的用户授权接口将用户信息保存到服务端
    4)保存后端接口返回的uid和unionid到localstorage中,作为全局参数

    获取用户的授权信息

    getUid:function(cf){
      var that = this
      wx.login({
       success: function (ress) {
        var code = ress.code 
        wx.getUserInfo({ 
         withCredentials: true,     
         success: function (res) {
          that.globalData.userInfo = res.userInfo;
          that.authorize(code, res.signature, res.iv, res.rawData, res.encryptedData, cf)
         }
        })
       }
      })
     },
     authorize: function (code, signature, iv, rawData, encryptedData, cf) {
      var that =this
      var dataobj = {
       code: code,
       signature: signature,
       iv: iv,
       raw_data: rawData,
       encrypted_data: encryptedData
      }
      console.log("code:",code)
      var param = JSON.stringify(dataobj)
      param = that.Encrypt(param)
      var url = that.data.API_DOMAIN2 + "/user/authorization?param=" + param
      wx.request({
       url: url,
       method: "GET",
       header: {
        'content-type': 'application/json'
       },
       success: function (res) {
        if (res.data.errcode == 200) {
         wx.hideToast()    
         wx.setStorage({
          key: "uid",
          data: res.data.data.uid,
          success: function () {
           if (cf) {
            typeof cf == "function"  cf(res.data.data.uid)
           }
          }
         })
        } else {
         that.exceptionHandle('uid', url, res.data.errcode, res.data.msg)
        }
       }
      })
     },

    服务端

    入口方法

    /**
       * api接口开发
       * 获取详情的接口
       * @param $uid 用户编号
       * @param $iv 向量
       * @param $encryptedData 微信加密的数据
       * @param $rawData 判断是否为今天
       * @param $signature 签名
       * @return array
       */
      public static function authorization($appid,$appsecret,$code,$iv,$encryptedData,$rawData,$signature){
        $result = self::decodeWxData($appid,$appsecret,$code,$iv,$encryptedData);
        if($result['errcode'] != 200){
          return $result;
        }
        //处理微信授权的逻辑
        $wxUserData = $result['data'];
        error_log("authorization data=============>");
        error_log(json_encode($wxUserData));
        $uid = WxaUserService::regWxaUser($wxUserData);
        $data['uid'] = $uid['uid'];
        $data['unionid'] = $uid['unionid'];
        $result['data'] = $data;
        return $result;
      }
      
      /**
       * 解密微信的数据
       * @param $code wx.login接口返回的code
       * @param $iv wx.getUserInfo接口或者wx.getWeRunData返回的iv
       * @param $encryptedData wx.getUserInfo接口或者wx.getWeRunData返回的加密数据
       * @return array
       */
      public static function decodeWxData($appid,$appsecret,$code,$iv,$encryptedData){
        $sessionKeyUrl = sprintf('%s?appid=%ssecret=%sjs_code=%sgrant_type=authorization_code',config('param.wxa_user_info_session_key_url'),$appid,$appsecret,$code);
        $rtnJson = curlRequest($sessionKeyUrl);
        $data = json_decode($rtnJson,true);
        error_log('authorization wx return data========>');
        error_log($rtnJson);
        if(isset($data['errcode'])){
          return $data;
        }
        $sessionKey = $data['session_key'];
        $wxHelper = new WxBizDataHelper($appid,$sessionKey,$encryptedData,$iv);
        $data['errcode'] = 200;
        $data['data'] = [];
        if(!$wxData = $wxHelper->getData()){
          $data['errcode'] = -1;
        }else{
          error_log('current wx return data is =========>'.json_encode($wxData));
          $data['data'] = $wxData;
        }
        return $data;
      }

    保存用户信息的方法

     /**
       * 保存用户信息的方法
       * @param $wxaUserData
       * @param $regFromGh 表示是否从公众号进行注册
       */
      public function regWxaUser($wxaUserData,$regFromGh = false)
      {
        $value = $wxaUserData['unionId'];
        $key = getCacheKey('redis_key.cache_key.zset_list.lock') . $value;
        $newExpire = RedisHelper::getLock($key);
        $data = $this->storeWxaUser($wxaUserData,$regFromGh);
        RedisHelper::releaseLock($key, $newExpire);
        return $data;
      }
      
      /**
       * 保存信息
       * @param $wxaUserData
       * @return mixed
       */
      public function storeWxaUser($wxaUserData,$regFromGh = false)
      {
        $wxUnionId = $wxaUserData['unionId'];
        if (!$user = $this->getByWxUnionId($wxUnionId)) {
          $getAccountDataStartTime = time();
          //这里是因为需要统一账户获取uid,所以这个是用户中心的接口,如果没有这个流程,则直接使用数据
          if($accountData = AccountCenterHelper::regWxaUser($wxaUserData)){
            $getAccountDataEndTime = time();
            $accountRegTime = $getAccountDataEndTime - $getAccountDataStartTime;
            error_log("reg user spend time is ===================>" . $accountRegTime);
            $user = [
              'uid' => $accountData['uid'],
              'user_name' => $accountData['user_name'],
              'nick_name' => $wxaUserData['nickName'],
              'sex' => $accountData['sex'],
              'wx_union_id' => $accountData['wx_union_id'],
              'avatar' => isset($accountData['avatar'])?$accountData['avatar']:"",
              'from_appid' => $accountData['from_appid'],
              'province' => $wxaUserData['province'],
              'city' => $wxaUserData['city'],
              'country' => $wxaUserData['country'],
              'openid' => $wxaUserData['openId'],
              'wx_header' => isset($wxaUserData['avatarUrl'])?$wxaUserData['avatarUrl']:"",
              'gh_openid' => $regFromGh?$wxaUserData['openId']:"",
            ];
            error_log("insert data=============>" . json_encode($user));
            $user = $this->store($user);
            $regApiUserEndTime = time();
            error_log(" reg api user spend time================>" . ($regApiUserEndTime - $getAccountDataEndTime));
            error_log(" after insert data=============>" . json_encode($user));
          }
        }else{
          if(!$user['wx_header']){
            $updateData = [
              'id' => $user['id'],
              'uid' => $user['uid'],
              'wx_header' => $wxaUserData['avatarUrl'],
            ];
            $this->update($updateData);
          }
          //同步用户的openid
          if($wxaUserData['openId'] != $user['openid']){
            $updateData = [
              'id' => $user['id'],
              'uid' => $user['uid'],
              'openid' => $wxaUserData['openId'],
            ];
            $this->update($updateData);
          }
        }
        $data['uid'] = $user['uid'];
        $data['unionid'] = $wxUnionId;
        return $data;
      }

    根据unionid获取用户信息

      /**
       * 根据unionid获取用户信息
       */
      public function getByWxUnionId($unionId)
      {
        $cacheKey = getCacheKey('redis_key.cache_key.wxa_user.info') . $unionId;
        $value = $this->remember($cacheKey, function () use ($unionId) {
          $userInfo = WxaUser::where('wx_union_id', $unionId)->first();
          $userInfo = $this->compactUserInfo($userInfo);
          return $userInfo;
        });
        return $value;
      }

    WxBizDataHelper工具类

    ?php
    /**
     * Created by PhpStorm.
     * User: Auser
     * Time: 11:17
     */
    
    namespace App\Http\Base\Wx;
    
    
    class WxBizDataHelper
    {
    
      private $appid;
      private $seesionKey ;
      private $encryptedData;
      private $iv;
      public function __construct($appid, $sessionKey,$encryptedData, $iv)
      {
        $this->appid = $appid;
        $this->seesionKey = $sessionKey;
        $this->encryptedData = $encryptedData;
        $this->iv = $iv;
      }
    
      public function getData(){
        $pc = new WXBizDataCrypt($this->appid, $this->seesionKey);
        $json = '';
        $errCode = $pc->decryptData($this->encryptedData, $this->iv, $json);
        $data = [];
        if ($errCode == 0) {
          $data = json_decode($json,true);
        }
        return $data;
      }
    
    
    }

    WXBizDataCrypt工具类

    ?php
    /**
     * Created by PhpStorm.
     * User: Auser
     * Time: 10:38
     */
    
    namespace App\Http\Base\Wx;
    
    use App\Http\Base\Wx\Prpcrypt;
    use App\Http\Base\Wx\ErrorCode;
    use App\Http\Base\Wx\PKCS7Encoder;
    class WXBizDataCrypt
    {
    
      private $appid;
      private $sessionKey;
    
      /**
       * 构造函数
       * @param $sessionKey string 用户在小程序登录后获取的会话密钥
       * @param $appid string 小程序的appid
       */
      public function __construct( $appid, $sessionKey)
      {
        $this->sessionKey = $sessionKey;
        $this->appid = $appid;
      }
    
    
      /**
       * 检验数据的真实性,并且获取解密后的明文.
       * @param $encryptedData string 加密的用户数据
       * @param $iv string 与用户数据一同返回的初始向量
       * @param $data string 解密后的原文
       *
       * @return int 成功0,失败返回对应的错误码
       */
      public function decryptData( $encryptedData, $iv, $data )
      {
        if (strlen($this->sessionKey) != 24) {
          return ErrorCode::$IllegalAesKey;
        }
        $aesKey=base64_decode($this->sessionKey);
    
    
        if (strlen($iv) != 24) {
          return ErrorCode::$IllegalIv;
        }
        $aesIV=base64_decode($iv);
    
        $aesCipher=base64_decode($encryptedData);
    
        $pc = new Prpcrypt($aesKey);
        $result = $pc->decrypt($aesCipher,$aesIV);
    
        if ($result[0] != 0) {
          return $result[0];
        }
    
        $dataObj=json_decode( $result[1] );
        if( $dataObj == NULL )
        {
          return ErrorCode::$IllegalBuffer;
        }
        if( $dataObj->watermark->appid != $this->appid )
        {
          return ErrorCode::$IllegalBuffer;
        }
        $data = $result[1];
        return ErrorCode::$OK;
      }
    
    }

    Prpcrypt工具类

    ?php
    /**
     * Created by PhpStorm.
     * User: Auser
     * Time: 10:55
     */
    
    namespace App\Http\Base\Wx;
    
    class Prpcrypt
    {
      public $key;
    
      public function __construct($key)
      {
        $this->key = $key;
      }
    
      /**
       * 对密文进行解密
       * @param string $aesCipher 需要解密的密文
       * @param string $aesIV 解密的初始向量
       * @return string 解密得到的明文
       */
      public function decrypt($aesCipher, $aesIV)
      {
    
        try {
          $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
          mcrypt_generic_init($module, $this->key, $aesIV);
          //解密
          $decrypted = mdecrypt_generic($module, $aesCipher);
          mcrypt_generic_deinit($module);
          mcrypt_module_close($module);
        } catch (Exception $e) {
          return array(ErrorCode::$IllegalBuffer, null);
        }
    
    
        try {
          $result = PKCS7Encoder2::decode($decrypted);
        } catch (Exception $e) {
          //print $e;
          return array(ErrorCode::$IllegalBuffer, null);
        }
        return array(0, $result);
      }
    }

    ErrorCode状态代码类

    ?php
    /**
     * Created by PhpStorm.
     * User: Auser
     * Time: 10:33
     */
    
    namespace App\Http\Base\Wx;
    
    
    class ErrorCode
    {
      public static $OK = 0;
      public static $IllegalAesKey = -41001;
      public static $IllegalIv = -41002;
      public static $IllegalBuffer = -41003;
      public static $DecodeBase64Error = -41004;
    
    }

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    您可能感兴趣的文章:
    • 微信小程序开发之获取用户手机号码(php接口解密)
    • 微信小程序发送订阅消息的方法(php 为例)
    • 基于PHP实现微信小程序客服消息功能
    • 微信小程序学习笔记之表单提交与PHP后台数据交互处理图文详解
    • PHP小程序支付功能完整版【基于thinkPHP】
    • PHP后台实现微信小程序登录
    • 微信小程序调用PHP后台接口 解析纯html文本
    • 微信小程序图片选择、上传到服务器、预览(PHP)实现实例
    • 微信小程序 PHP后端form表单提交实例详解
    • PHP:微信小程序 微信支付服务端集成实例详解及源码下载
    • PHP小程序后台部署运行 LNMP+WNMP的方法
    上一篇:统计PHP目录中的文件数方法
    下一篇:浅谈php://filter的妙用
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    PHP实现微信小程序用户授权的工具类示例 PHP,实现,微信,小,程序,用户,