ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于ThinkPHP的微信公众号第三方代授权核心技术实现

基于ThinkPHP的微信公众号第三方代授权核心技术实现 简介这是一份基于Thinkphp框架开发的微信公众号第三方代授权源码包目标用户是需要为公众号接入第三方平台能力的PHP研发人员可有效解决第三方授权过程中授权回调、签名校验、消息体加解密等常见环节实现繁琐的问题。整个资源以zip压缩包形式发布仅7KB大小包含2个php文件分别承担主流程入口与微信官方加解密算法封装结构独立清晰可直接复制到已有Thinkphp项目中使用也能作为二次开发的基础脚手架。代码虽然精简却覆盖了授权参数接收、验签处理以及消息加解密调用等关键路径读者可通过源码快速掌握微信第三方平台与公众号交互的底层原理并沉淀出处理签名错误、解密失败等异常的经验方法。目前已有887人浏览学习主要适合熟悉Thinkphp基础、正在开发公众号第三方管理后台或独立代授权系统的工程技术人员。下载并阅读该源码既能缩短授权模块的搭建周期也能为后续功能扩展提供可靠参考尤其适合正在接手公众号第三方平台项目或准备自行封装授权组件的开发者。1. 为什么需要第三方代授权从账号密码托管说起做过微信公众号开发的都知道早期给客户做公众号功能最直接的方式就是让客户把账号密码给你你登录公众平台后台拿到AppID和AppSecret然后把服务器IP加到白名单里开始调接口。流程简单直接一套代码能跑就能交付。但真实业务里这套玩法越来越跑不通了。一方面客户对账号密码的安全意识变强谁都不愿意把运营账号随手交给外包团队尤其是涉及支付、模板消息、用户数据这类敏感权限另一方面微信官方对登录风控持续收紧异地登录、频繁登录都会触发验证甚至封禁提醒你把客户的号搞出风险提示后续关系会相当尴尬。代授权模式的本质是把“账号密码托管”升级成“权限托管”。客户通过微信官方的扫码授权流程在微信生态内完成确认你的服务器拿到的是客户的公众号授权凭证authorizer_access_token 和 authorizer_refresh_token而不是账号密码。这个设计既符合微信平台规范也避免了你接触客户敏感凭据在合规性上更站得住脚。用 ThinkPHP 来实现这套流程在 PHP 生态里属于比较典型的中台业务。国内大量做小程序、公众号代运营、私域工具的服务商技术栈基本跑不掉 PHP而 ThinkPHP 又是国内使用最广的 PHP 框架之一。这篇文章我就基于实际项目经验把微信公众号第三方代授权业界也叫“代公众号实现业务”的核心链路、数据表设计和踩坑点完整梳理一遍。适合阅读这篇文章的人有两类一类是接外包项目、需要帮客户快速接入公众号功能的开发者另一类是自己做SaaS服务、需要同时管理多个公众号授权和调用凭证的技术负责人。前者可以解决燃眉之急后者可以从数据表设计、凭证刷新机制上规避很多后期运维问题。2. 代授权链路全貌一次扫码背后的四次握手在写代码之前先把整个授权链路的参与方和时序理清楚这是全网教程里讲得最少、但恰恰是最重要的部分。第三方代授权涉及三个参与方微信开放平台不是公众平台是另一套体系。第三方平台在这里创建审核通过后会拿到自己的 ComponentAppID 和 ComponentAppSecret同时平台会生成一个 ComponentVerifyTicket每10分钟推送一次到你的服务器。公众号管理员也就是你的客户他们用微信扫码确认授权。你的服务器第三方平台接收微信推送、换取授权凭证、代公众号调用接口。整条链路可以拆成四次关键交互第一步接收 ComponentVerifyTicket。这是所有流程的起点。微信开放平台在第三方平台创建成功后会定时往你配置的授权事件接收URL推送一个加密的 ticket 字符串。这个 ticket 是后续换取接口调用凭证的必需品必须妥善存储。第二步获取 component_access_token。用 ComponentAppID、ComponentAppSecret 和 ComponentVerifyTicket 三者换一个第三方平台全局凭证有效期2小时。这个凭证代表的是“你这个服务商”的身份不是你客户公众号的身份。第三步客户扫码授权。把客户引导到微信的授权页面客户用管理员微信扫码确认微信服务器会往你的授权回调URL推送一个 authorization_code这个 code 有效期只有10分钟得赶紧处理。第四步换取 authorizer_access_token 和 authorizer_refresh_token。用 authorization_code 换取客户公众号的访问凭证和刷新凭证。access_token 有效期2小时refresh_token 有效期30天但每次刷新都会轮换也就是说每次用 refresh_token 换完新凭证后旧的就失效了。把这四次交互串起来看代授权的核心本质是微信用 ComponentVerifyTicket 识别你的服务商身份用 authorization_code 确认客户愿意把公众号托付给你再用 refresh_token 轮换机制保证你长期可用但随时可收回。理解了这个底层逻辑后面写代码时就不会搞混各种凭证的职责。普通公众号开发模式和第三方代授权模式的凭证体系对比凭证普通模式代授权模式平台身份凭证无直接用公众号 AppSecretcomponent_access_token公众号身份凭证appid appsecret 换取authorization_code 换取刷新机制手动换新旧 token 失效refresh_token 自动轮换敏感信息需要客户提供 AppSecret无需客户提供任何密钥多公众号管理每个号一套配置统一授权集中管理这个对比能直观看出两种模式的差异。普通模式适合自营单个公众号代授权模式适合服务商同时托管几十上百个公众号的场景。3. 数据表设计凭证存储决定了后期运维的难易很多人做代授权功能时把表结构想简单了就一张表存 openid 和 token结果上线后刷新失败、授权过期、无法排查问题最后只能清库重来。我在项目中反复调整后沉淀下来的表结构分为三块第三方平台配置表、授权方信息表、凭证缓存表。3.1 第三方平台配置表这张表存的是你自己在微信开放平台创建的那个第三方平台的信息一般单条记录就够了。字段类型说明idint主键component_app_idvarchar(64)第三方平台 AppIDcomponent_app_secretvarchar(128)第三方平台 AppSecretcomponent_verify_tickettext微信推送的 ticket每次更新覆盖component_access_tokenvarchar(255)第三方平台接口调用凭证component_access_token_expiresint凭证过期时间戳verify_ticket_updated_atintticket 更新时间用于排查推送异常created_at / updated_atint记录时间有一点要提醒component_access_token 不要频繁请求官方接口有每天调用次数限制2000次/天。一次请求拿到的 token 只管2小时所以正确做法是存起来反复用快过期了才去刷新。3.2 授权方信息表这张表是整个功能的核心每一条记录代表一个已授权给你的公众号。字段类型说明idint主键app_idvarchar(64)授权方公众号的 AppIDnick_namevarchar(128)公众号昵称head_imgvarchar(255)公众号头像user_namevarchar(128)原始IDgh_开头aliasvarchar(128)微信号principal_namevarchar(128)主体名称authorize_refresh_tokentext刷新凭证30天轮换authorize_access_tokenvarchar(255)访问凭证authorize_access_token_expiresint访问凭证过期时间戳func_infotext公众号授权给第三方的权限集is_verifiedtinyint是否认证号影响接口权限statustinyint授权状态1正常0取消授权created_at / updated_atint记录时间这里有个字段需要特别说明func_info存的是授权权限集JSON比如有没有获取用户基本信息权限、有没有微信支付权限、有没有模板消息权限。这个字段在你后续开发功能时非常重要因为不同公众号的权限不一样有些客户的服务号没认证很多接口调不通你得在后台对这些客户做降级处理而不是直接报错。3.3 凭证缓存表有人会问authorizer_access_token 和 component_access_token 都存业务表里了为什么还要单独的缓存表原因在于当你一个第三方平台下挂着几百个公众号每次调用接口前都要查业务表如果业务表数据量大了查询就会成为性能瓶颈。更关键的是多个进程同时读写同一行的 access_token 字段会出现并发覆盖问题导致 token 提前失效。我在项目里用 ThinkPHP 自带的缓存机制来解决这个问题直接使用 Redis 驱动键名这样设计// 第三方平台凭证缓存 $cacheKey wx:component:access_token: . $componentAppId; // 授权方凭证缓存 $cacheKey wx:authorizer:access_token: . $authorizerAppId;缓存有效期设置为7000秒官方 token 有效期7200秒留200秒余量提前刷新也可以用 ThinkPHP 的Cache::set($key, $value, 7000)来实现。用缓存层的好处很明显并发环境下 Redis 的原子性操作避免了多个请求同时刷新 token 的问题也能显著降低数据库查询压力。我们在实际压测中几百个公众号的凭证查询响应时间从 80ms 降到了 2ms 以下。4. 核心代码实现ThinkPHP 6 下的完整授权链路理论讲了一堆现在上干货。下面的代码基于 ThinkPHP 6.0 LTS 版本是我在实际项目中验证过的完整实现。4.1 接收授权事件和 component_verify_ticket微信开放平台会向你的授权事件接收URL推送两种事件component_verify_ticket和authorized授权/取消授权。用一个控制器方法统一接收。?php declare(strict_types1); namespace app\api\controller; use think\facade\Cache; use think\facade\Db; use think\facade\Log; class WxComponent { // 微信开放平台配置 private $componentAppId 你的component_app_id; private $componentAppSecret 你的component_app_secret; /** * 接收微信推送的授权事件和ticket * 请求方式: POST * Content-Type: text/xml */ public function receiveEvent() { $postXml file_get_contents(php://input); Log::info(微信推送原始数据: . $postXml); if (empty($postXml)) { return fail; } // 解析XML libxml_disable_entity_loader(true); $xmlObj simplexml_load_string($postXml, SimpleXMLElement, LIBXML_NOCDATA); if ($xmlObj false) { Log::error(XML解析失败: . $postXml); return fail; } $infoType (string)$xmlObj-InfoType; $appId (string)$xmlObj-AppId; switch ($infoType) { case component_verify_ticket: $ticket (string)$xmlObj-ComponentVerifyTicket; $this-handleVerifyTicket($appId, $ticket); break; case authorized: // 授权成功客户扫码确认后触发 $authorizerAppId (string)$xmlObj-AuthorizerAppid; $authorizationCode (string)$xmlObj-AuthorizationCode; $this-handleAuthorized($authorizerAppId, $authorizationCode); break; case unauthorized: // 取消授权需要更新本地授权状态 $authorizerAppId (string)$xmlObj-AuthorizerAppid; $this-handleUnauthorized($authorizerAppId); break; case updateauthorized: // 授权更新如重新授权、修改权限集 $authorizerAppId (string)$xmlObj-AuthorizerAppid; $authorizationCode (string)$xmlObj-AuthorizationCode; $this-handleAuthorized($authorizerAppId, $authorizationCode); break; } return success; } /** * 保存 component_verify_ticket */ private function handleVerifyTicket($appId, $ticket) { if (empty($ticket)) { Log::error(ticket为空); return; } Db::name(wechat_component) -where(component_app_id, $this-componentAppId) -update([ component_verify_ticket $ticket, verify_ticket_updated_at time() ]); Log::info(ticket更新成功); // ticket更新后立即刷新component_access_token $this-refreshComponentToken(); } /** * 获取 component_access_token带缓存 */ public function getComponentAccessToken() { $cacheKey wx:component:access_token: . $this-componentAppId; $token Cache::get($cacheKey); if (!empty($token)) { return $token; } return $this-refreshComponentToken(); } /** * 刷新 component_access_token */ public function refreshComponentToken() { $url https://api.weixin.qq.com/cgi-bin/component/api_component_token; $url sprintf( https://api.weixin.qq.com/cgi-bin/component/api_component_token ); $data [ component_appid $this-componentAppId, component_appsecret $this-componentAppSecret, component_verify_ticket $this-getLatestTicket() ]; $result $this-httpPost($url, json_encode($data, JSON_UNESCAPED_UNICODE)); $result json_decode($result, true); if (isset($result[component_access_token])) { $cacheKey wx:component:access_token: . $this-componentAppId; // 有效7200秒缓存7000秒提前刷新 Cache::set($cacheKey, $result[component_access_token], 7000); return $result[component_access_token]; } Log::error(获取component_access_token失败: . json_encode($result)); return ; } /** * 获取最新的 component_verify_ticket */ private function getLatestTicket() { $row Db::name(wechat_component) -where(component_app_id, $this-componentAppId) -find(); return $row ? $row[component_verify_ticket] : ; } /** * POST请求封装 */ public function httpPost($url, $data) { $ch curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, [Content-Type: application/json]); $response curl_exec($ch); $error curl_error($ch); curl_close($ch); if ($error) { Log::error(curl请求失败: . $error); return ; } return $response; } }这里有一个在实际部署中特别容易踩的坑接收微信推送的接口千万别加 CSRF 验证、签名验证或登录态校验。微信服务器是通过 URL 直接 POST 过来的不带你的 Session你加了自定义验证逻辑推送直接被拦截ticket 收不到后续所有流程都会卡死。4.2 预授权码和构造授权页面客户扫码授权不是直接跳微信官方那个固定授权页而是要先通过接口拿一个pre_auth_code拼到授权链接里。/** * 获取预授权码 */ public function getPreAuthCode() { $componentAccessToken $this-getComponentAccessToken(); $url https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token . $componentAccessToken; $data [ component_appid $this-componentAppId ]; $result $this-httpPost($url, json_encode($data)); $result json_decode($result, true); if (isset($result[pre_auth_code])) { return $result[pre_auth_code]; } Log::error(获取pre_auth_code失败: . json_encode($result)); return ; } /** * 生成授权页面跳转链接 */ public function buildAuthUrl($redirectUri) { $preAuthCode $this-getPreAuthCode(); // $redirectUri 需要 URL 编码 $authUrl sprintf( https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid%spre_auth_code%sredirect_uri%s, $this-componentAppId, $preAuthCode, urlencode($redirectUri) ); return $authUrl; }实际项目中客户在授权页面可以选择授权给哪些权限。如果你的业务只需要基础接口权限建议在跳转时不加auth_type参数或设置为1让客户能快速完成授权避免复杂权限选择导致流失。如果业务确实需要高级权限比如获取用户手机号再设置为2或3。4.3 回调处理用授权码换取公众号凭证客户扫码确认后微信会往你配置的授权回调URL跳转并带上auth_code。这个 code 的有效期只有10分钟所以回调处理接口必须高效尽量不要做太重的业务逻辑。/** * 授权回调处理 * 地址: /api/wxComponent/authCallback */ public function authCallback() { $authCode request()-param(auth_code); $expiresIn request()-param(expires_in); if (empty($authCode)) { return 授权失败缺少auth_code; } $result $this-exchangeAuthCode($authCode); if (empty($result)) { return 授权失败换取凭证异常; } // 跳转到你自己的成功页面 return redirect(/admin/wechat/list?auth_success1); } /** * 用auth_code换取授权方access_token和refresh_token */ private function exchangeAuthCode($authCode) { $componentAccessToken $this-getComponentAccessToken(); $url https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token . $componentAccessToken; $data [ component_appid $this-componentAppId, authorization_code $authCode ]; $result $this-httpPost($url, json_encode($data)); $result json_decode($result, true); if (isset($result[authorization_info])) { $authInfo $result[authorization_info]; $authorizerAppId $authInfo[authorizer_appid]; $accessToken $authInfo[authorizer_access_token]; $expiresIn $authInfo[expires_in]; $refreshToken $authInfo[authorizer_refresh_token]; $funcInfo json_encode($authInfo[func_info], JSON_UNESCAPED_UNICODE); // 保存到授权方表 $this-saveAuthorizer($authorizerAppId, $accessToken, $expiresIn, $refreshToken, $funcInfo); return true; } Log::error(换取授权方token失败: . json_encode($result)); return ; } /** * 保存或更新授权方信息 */ private function saveAuthorizer($authorizerAppId, $accessToken, $expiresIn, $refreshToken, $funcInfo) { $expiresAt time() intval($expiresIn) - 200; $authorizer Db::name(wechat_authorizer) -where(app_id, $authorizerAppId) -find(); if ($authorizer) { Db::name(wechat_authorizer) -where(app_id, $authorizerAppId) -update([ authorize_access_token $accessToken, authorize_access_token_expires $expiresAt, authorize_refresh_token $refreshToken, func_info $funcInfo, status 1, updated_at time() ]); } else { // 获取公众号基本信息 $baseInfo $this-getAuthorizerInfo($authorizerAppId, $accessToken); Db::name(wechat_authorizer)-insert([ app_id $authorizerAppId, nick_name $baseInfo[nick_name] ?? , head_img $baseInfo[head_img] ?? , user_name $baseInfo[user_name] ?? , alias $baseInfo[alias] ?? , principal_name $baseInfo[principal_name] ?? , authorize_access_token $accessToken, authorize_access_token_expires $expiresAt, authorize_refresh_token $refreshToken, func_info $funcInfo, is_verified $baseInfo[is_verified] ?? 0, status 1, created_at time(), updated_at time() ]); } // 缓存access_token $cacheKey wx:authorizer:access_token: . $authorizerAppId; Cache::set($cacheKey, $accessToken, intval($expiresIn) - 200); }4.4 刷新 authorizer_access_token 的定时任务authorizer_access_token有效期只有2小时authorizer_refresh_token有效期30天且轮换。这意味着你必须在30天内至少手动或自动刷新一次否则授权就彻底失效了需要客户重新扫码。我的处理方式是在 ThinkPHP 的命令行任务里配置一个定时任务每1小时执行一次刷新逻辑。?php declare(strict_types1); namespace app\command; use think\console\Command; use think\console\Input; use think\console\Output; use think\facade\Db; class RefreshAuthorizerToken extends Command { protected function configure() { $this-setName(wechat:refresh_token) -setDescription(刷新所有授权方access_token); } protected function execute(Input $input, Output $output) { $now time(); // 找出过期时间在30分钟内的授权方 $list Db::name(wechat_authorizer) -where(status, 1) -where(authorize_access_token_expires, , $now 1800) -limit(200) -select(); $output-writeln(需要刷新的授权方数量: . count($list)); // 实例化公共控制器里的方法 $component new \app\common\service\WechatComponentService(); foreach ($list as $item) { $result $component-refreshAuthorizerToken( $item[app_id], $item[authorize_refresh_token] ); if ($result false) { $output-writeln(刷新失败: . $item[app_id]); // 连续失败多次可发送告警通知 continue; } $output-writeln(刷新成功: . $item[app_id]); } $output-writeln(任务执行完成); } }对应的刷新方法/** * 刷新授权方access_token */ public function refreshAuthorizerToken($authorizerAppId, $refreshToken) { $componentAccessToken $this-getComponentAccessToken(); $url https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token . $componentAccessToken; $data [ component_appid $this-componentAppId, authorizer_appid $authorizerAppId, authorizer_refresh_token $refreshToken ]; $result $this-httpPost($url, json_encode($data)); $result json_decode($result, true); if (isset($result[authorizer_access_token])) { $newAccessToken $result[authorizer_access_token]; $newRefreshToken $result[authorizer_refresh_token]; $expiresIn $result[expires_in]; Db::name(wechat_authorizer) -where(app_id, $authorizerAppId) -update([ authorize_access_token $newAccessToken, authorize_refresh_token $newRefreshToken, authorize_access_token_expires time() intval($expiresIn) - 200, updated_at time() ]); $cacheKey wx:authorizer:access_token: . $authorizerAppId; Cache::set($cacheKey, $newAccessToken, intval($expiresIn) - 200); return true; } Log::error(刷新授权方token失败: . json_encode($result)); return false; }定时任务在 ThinkPHP 6 里的配置方法是在config/console.php里注册命令类然后用 crontab 执行*/30 * * * * php /你的项目路径/think wechat:refresh_token /你的项目路径/runtime/logs/refresh_token.log 215. 代授权后的接口调用示例以获取用户 OpenID 为例凭证体系搭好了最终是要拿来干活的。这里以最常见的网页授权获取用户 OpenID 为例演示在代授权模式下如何调用接口。在第三方代授权模式下网页授权的流程和普通模式有个关键区别普通模式直接使用公众号的 appid 和 secret 换取网页授权 access_token代授权模式则需要先用 authorizer_access_token 换取网页授权凭证或者直接使用开放平台能力。/** * 代授权模式下获取用户OpenID */ public function getOpenId($code, $authorizerAppId) { // 获取该公众号的authorizer_access_token $authorizerTokenService new \app\common\service\WechatComponentService(); $accessToken $authorizerTokenService-getAuthorizerAccessToken($authorizerAppId); // 使用authorizer_access_token调用网页授权接口 $url sprintf( https://api.weixin.qq.com/sns/oauth2/access_token?appid%scode%sgrant_typeauthorization_codecomponent_appid%scomponent_access_token%s, $authorizerAppId, $code, $this-componentAppId, $componentAccessToken ); $result $this-httpGet($url); $result json_decode($result, true); if (isset($result[openid])) { return $result[openid]; } Log::error(获取OpenID失败: . json_encode($result)); return ; }注意上面 URL 里的参数比普通模式多了component_appid和component_access_token这两个参数。这是代授权模式下网页授权最大的区别很多第一次做的人会漏掉导致一直报 40029 或 48001 错误。如果只是拿基础用户信息头像、昵称用sns/userinfo接口也可以但要注意微信对用户隐私政策的调整——未认证公众号和2021年后新注册的公众号即使拿到 openid也无法获取用户头像和昵称只能拿到 UnionID 体系下的 openid。你在设计功能时要考虑到这个限制不能默认所有用户信息都拿得到。6. 踩过的坑排查链路的完整复盘最后分享几个我在实际项目里踩过的坑这些坑网上基本没人系统讲过但遇到了会浪费大量时间。6.1 component_verify_ticket 收不到的排查现象开放平台配置好授权事件URL后服务器日志里完全没有微信推送的请求记录。我的排查链路是先确认 URL 是否公网可访问用浏览器直接 GET 访问一下再看服务器防火墙是否放行 POST 请求然后看 Nginx 日志里有没有对应记录最后检查代码里有没有加额外的验证逻辑。最终的原因很搞笑我在接收接口里加了 Laravel 风格的自定义签名验证中间件微信的推送不带签名直接就 403 了。去掉后问题解决。经验总结接收微信推送的接口要保证干净、纯粹不要加任何自定义鉴权逻辑。6.2 authorizer_refresh_token 突然失效现象某客户公众号的 token 刷新失败报61003 reflesh_token 已被使用。原因分析refresh_token 是轮换制的每次刷新后旧的就失效了。如果服务器上有多套定时任务、多个进程同时去刷新同一个公众号的 token就会出现一个进程用旧 token 刷新成功、另一个进程拿着同一个旧 token 又去刷新第二次必然失败。解决办法在数据库加一个refresh_token_version字段每次刷新前比对版本号版本不一致就跳过或者用 Redis 的分布式锁控制同一公众号的刷新操作只能有一个进程执行。6.3 缓存和数据库的 token 不一致现象缓存里还是旧的 access_token但数据库里已经是新的了导致接口调用一直报 token 无效。这其实是我在设计缓存时没想清楚导致的。缓存键应该包含 token 本身的内容而不是只依赖 appid。// 错误做法只依赖appid $cacheKey wx:token: . $authorizerAppId; // 正确做法把token内容作为缓存键的一部分 $token $authorizerTokenService-getAuthorizerAccessToken($authorizerAppId); $cacheKey wx:token: . md5($authorizerAppId . $token);这样就算数据库被更新了只要 token 变了缓存键就变了不会存在读旧缓存的问题。6.4 静默授权下拿不到用户 UnionID网页授权分静默snsapi_base和非静默snsapi_userinfo两种。在非静默授权下能拿到用户的完整信息静默授权只能拿到 openid。但如果你的业务是跨公众号打通用户体系就需要用户的 UnionID。在代授权模式下同一开放平台账号下的多个公众号、小程序用户 UnionID 是一致的。这就要求你引导用户在开放平台完成账号绑定否则不同公众号下同一个用户的 openid 不一样数据就串不起来了。7. 关于授权状态监控的最后一点建议代码写完、功能上线这只是开始。代授权模式下最怕的是客户的授权静默失效——你没有收到unauthorized推送但 refresh_token 因为长期没刷新过期了结果客户公众号的定时推送、自动回复全部挂掉用户投诉一堆。所以我强烈建议做一个授权健康度的监控看板。核心指标就两个授权状态正常率已授权公众号中 token 刷新成功的占比和授权即将到期提醒refresh_token 距离过期不足5天的列表。前者用定时任务冲数据到独立缓存表后者在管理后台每天提醒运营人员主动联系客户重新扫码。另一件容易被忽略的事是微信开放平台对第三方的权限集调整。客户在重新授权时可以勾选或取消部分权限如果客户把某个权限关了你这边调用对应接口就会报错。所以每次收到updateauthorized推送除了更新 token还要把最新的func_info存下来并同步到你内部的功能开关表里。整体做完这套代授权系统你会明显感受到它带来的运维便利不需要客户提供任何账号密码不需要登录公众平台后台管理几十个公众号都只需要自己一个后台界面。但便利的前提是你对凭证体系、刷新机制、异常补偿有足够清晰的认知而不是把官方文档抄一遍就收工。本文还有配套的精品资源点击获取
返回列表