platform = model('Platform')->where(['id'=>$platform_id])->find()){ throw new \Exception('获取平台信息失败'); } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 取得平台信息',$platform_id,$channel_id)); //获取渠道信息 if(!$this->adminConfig = model('AdminConfig')->where(['admin_id'=>$channel_id])->find()){ throw new \Exception('获取用户信息失败'); } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 取得渠道信息',$platform_id,$channel_id)); $wechatObj = new WeChatObject($this->adminConfig); $this->weChat = $wechatObj->getPlatform($platform_id); } /** * 授权处理 * @param bool $isUpdate 是否是更新权限 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function authorization($isUpdate = false){ // 使用授权码换取接口调用凭据和授权信息 $auth = $this->weChat->handleAuthorize(); // 检查当前授权的公众号与历史授权公众号是否一致 $existsAppID = model('AdminConfig')->where('appid',$auth['authorization_info']['authorizer_appid'])->where('admin_id','neq',$this->adminConfig->admin_id)->find(); if($existsAppID){ //更新平台用户refreshToken信息 $this->updateUserRefrshToken($this->platform->id,$auth['authorization_info']['authorizer_refresh_token'],$existsAppID['admin_id']); throw new \Exception('一个服务号只能绑定一个账号!'); } if ($this->adminConfig->appid && $this->adminConfig->appid != $auth['authorization_info']['authorizer_appid']) { throw new \Exception('当前授权的公众号与历史授权公众号不一致!'); } // 获取授权方的帐号基本信息 $authInfo = $this->weChat->getAuthorizer($auth['authorization_info']['authorizer_appid']); Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 微信授权检测通过',$this->platform['id'],$this->adminConfig['admin_id'])); //检测权限 $this->checkWeChatAuth($authInfo); //更新平台用户refreshToken信息 $this->updateUserRefrshToken($this->platform->id,$auth['authorization_info']['authorizer_refresh_token']); $data['appid'] = $auth['authorization_info']['authorizer_appid']; $data['json'] = $authInfo; if(!$this->adminConfig->save($data)){ throw new \Exception('更新授权信息失败'); } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 微信基本信息更新完成',$this->platform['id'],$this->adminConfig['admin_id'])); //检查默认平台 if($this->platform['id'] == $this->adminConfig['platform_id'] && !$isUpdate){ try { //同步微信用户 $this->syncWeChatUsers($this->adminConfig['admin_id'],$auth['authorization_info']['authorizer_appid']); $menu = []; //检测是否是单独配置菜单域名 if(isset($this->adminConfig['menuophost_id']) && $this->adminConfig['menuophost_id']){ if($ophost = model('Ophost')->where('id',$this->adminConfig['menuophost_id'])->find()){ $menu = json_decode(str_replace('cpsurl', config('site.scheme'). '://' .$auth['authorization_info']['authorizer_appid'].'.'.$ophost['host'], config('site.wx_menu')), true); } }else{ $menu = json_decode(config('site.wx_menu'), true); foreach($menu as $key => $val){ if(isset($val['url'])){ $menu[$key]['url'] = $this->getWeChatMenuUrl($this->platform->id,$auth['authorization_info']['authorizer_appid'],$val['url']); } if(isset($val['sub_button']) && !empty($val['sub_button'])){ foreach($val['sub_button'] as $sub_k => $sub_v){ if(isset($sub_v['url'])){ $menu[$key]['sub_button'][$sub_k]['url'] = $this->getWeChatMenuUrl($this->platform->id,$auth['authorization_info']['authorizer_appid'],$sub_v['url']); } } } } } //默认平台时更新菜单 $data['wx_menu'] = $this->updateUserWeChatMenu($auth['authorization_info']['authorizer_appid'], $auth['authorization_info']['authorizer_refresh_token'],$menu); if (!$this->adminConfig->save($data)) { Log::error('授权时,更新微信菜单失败2'); } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 微信菜单数据更新完成',$this->platform['id'],$this->adminConfig['admin_id'])); }catch (\Exception $exception){ Log::notice($exception->getMessage()); Log::notice('授权时,更新微信菜单失败1'); } } model('AdminConfig')->delAdminInfoAllCache($this->adminConfig->admin_id); //添加微信AD数据源 WeChatAdService::instance()->createChannelWxAdSourceId($this->adminConfig['admin_id']); //清除缓存 $redis = Redis::instance(); $redis->del('AA:' . $auth['authorization_info']['authorizer_appid']); } /** * 更新用户微信菜单 * @param $app_id * @param $refresh_token * @param $menu * @return bool|mixed */ private function updateUserWeChatMenu($app_id,$refresh_token,$menu){ //获取用户公众号 $officialAccount = $this->weChat->officialAccount($app_id, $refresh_token); $officialAccount->http_client = new Client(Config::get('wechat.http')); $officialAccount['cache'] = new RedisCache(Redis::instanceCache()); $officialAccount->menu->delete(); //删除全部菜单 主要是掌中云个 性化菜单 $ret = $officialAccount->menu->create($menu); if (!$ret || $ret['errcode'] != 0) { return null; }else{ $menu = WeChatMenu::rechargeMenuFilter($menu); if(!empty($menu)){ $ret = $officialAccount->menu->create($menu,['client_platform_type' => 1]); } } if (!$ret || (isset($ret['errcode']) && $ret['errcode'] != 0)) { return null; } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 微信菜单更新完成',$this->platform['id'],$this->adminConfig['admin_id'])); return $menu; } /** * 获取菜单URL * @param $platform_id * @param $app_id * @param $redirect * @return string */ private function getWeChatMenuUrl($platform_id,$app_id,$redirect){ $redirect = str_replace('cpsurl', '', $redirect); $webParams = []; $entryHost = model('Entryhost')->getInfo(); if($entryHost){ $webSite = config('site.scheme'). '://' .$entryHost['host']; $webParams['channel_id'] = $this->adminConfig->admin_id; }else{ if($ophost = model('Ophost')->getInfo($platform_id,$this->adminConfig->ophost_id)){ $webSite = \think\Config::get('site.scheme').'://'.$app_id.'.'.$ophost['host']; }else{ $webSite = ''; } } if($redirect){ $pathParams = parse_url($redirect); //添加路径 if(isset($pathParams['path']) && $pathParams['path']){ $webSite .= $pathParams['path']; } //检查路径是否有参数 if(isset($pathParams['query']) && $pathParams['query']){ $pathQuery = explode('&',$pathParams['query']); if($pathQuery){ foreach($pathQuery as $val){ $temp = explode('=',$val); $webParams[$temp[0]] = $temp[1] ?? ''; } } } } if($webParams){ $webSite .= '?'.http_build_query($webParams); } return $webSite; } /** * 更新用户RefrshToken * @param $platform_id * @param $refresh_token * @param $admin_id * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @throws \Exception */ private function updateUserRefrshToken($platform_id,$refresh_token,$admin_id = null){ //更新ptoken信息 $ptoken_map = ['admin_id'=>$this->adminConfig->admin_id,'platform_id'=>$platform_id]; if($admin_id){ $ptoken_map['admin_id'] = $admin_id; } if($ptoken = model('Ptoken')->where($ptoken_map)->find()){ if(false === model('Ptoken')->where($ptoken_map)->update(['refresh_token'=>$refresh_token,'updatetime'=>time()])){ throw new \Exception('更新RefrshToken失败'); } }else{ $insert_data = array_merge($ptoken_map,['refresh_token' => $refresh_token,'createtime'=>time(),'updatetime'=>time()]); if(!model('Ptoken')->insert($insert_data)){ throw new \Exception('写入RefrshToken失败'); } } Log::info(sprintf('微信授权: platform_id:%d channel_id:%d 微信PTOKEN更新完成',$this->platform['id'],$this->adminConfig['admin_id'])); } /** * 检测权限 * @param $authUser * @throws \Exception */ private function checkWeChatAuth($authUser){ if (!isset($authUser['authorizer_info']['service_type_info']['id'])) { throw new \Exception('获取授权信息失败,请重新扫码授权'); } if ($authUser['authorizer_info']['service_type_info']['id'] != 2) { throw new \Exception('当前授权公众号类型非服务号,请使用服务号进行扫码'); } if ($authUser['authorizer_info']['verify_type_info']['id'] == -1) { throw new \Exception('当前授权服务号未认证,请使用认证服务号进行扫码'); } $authList = array_column(array_column($authUser['authorization_info']['func_info'], 'funcscope_category'), 'id'); if(empty($authList)){ throw new \Exception('获取授权信息失败'); } if(!in_array(1,$authList)){ throw new \Exception('必须授予-消息管理权限'); } if(!in_array(15,$authList)){ throw new \Exception('必须授予-自定义菜单权限'); } if(!in_array(4,$authList)){ throw new \Exception('必须授予-网页服务权限'); } if(!in_array(2,$authList)){ throw new \Exception('必须授予-用户管理权限'); } if(!in_array(3,$authList)){ throw new \Exception('必须授予-帐号服务权限'); } if(!in_array(11,$authList)){ throw new \Exception('必须授予-素材管理权限'); } if(!in_array(23,$authList)){ throw new \Exception('必须授予-广告管理权限'); } } private function syncWeChatUsers($channel_id,$appid){ if(!model('SyncUser')->where(['admin_id'=>$channel_id,'appid'=>$appid])->find()){ $mq = new Rabbitmq(); $mq->send(['channel_id'=>$channel_id,'appid'=>$appid],self::SYNC_MQ_QUEUE_NAME,self::SYNC_MQ_EXCHANGE_NAME); Log::info('syncUser->Queue: Channel_id:'.$channel_id.' AppID:'.$appid.' 添加微信用户同步任务'); }else{ Log::info('syncUser->Queue: Channel_id:'.$channel_id.' AppID:'.$appid.' 已同步过微信用户'); } } }