微信公众号开发中,网页授权是获取用户身份最常用的手段。很多项目最初为了体验流畅,选择snsapi_base静默授权,只拿一个openid就够用了。随着业务发展,需要在页面上展示用户昵称、头像,甚至做个性化推荐时,就必须把scope升级为snsapi_userinfo。这个升级看似只改一个参数,实际涉及授权链接调整、用户确认、接口调用链路变化等多个环节,处理不当容易出现40029、10005等错误码。本文将从原理到代码,完整梳理升级流程。

一、先搞清楚snsapi_base和snsapi_userinfo的本质区别
网页授权本质上是OAuth2.0协议的一种实现,scope参数决定了授权的深度。snsapi_base是基础授权,用户完全无感知,页面不会弹出任何确认框,授权后只能拿到openid,适用于登录态识别、记录访问等对用户信息无要求的场景。
snsapi_userinfo则是完整授权,用户首次进入时会弹出授权确认页面,用户点击同意后,除了openid,还可以通过接口拉取昵称、头像、性别、所在城市等信息。需要特别注意:必须是关注了公众号的用户,或者用户主动同意过授权,才能成功拉取userinfo,否则接口会返回错误。
两者的授权链接格式完全相同,区别只在scope参数取值。还有一个关键点是access_token的概念区分:网页授权的access_token和基础支持的access_token(调用全局接口用的那个)是两个完全不同的东西,不能混用,缓存的key一定要分开存储,这是升级改造时最容易踩的坑。
二、升级后完整的授权流程与接口调用
升级到snsapi_userinfo后,整个授权链路变成四步:构造授权链接跳转、通过code换取access_token和openid、必要时刷新access_token、拉取用户信息。下面逐步展开。
第一步,构造授权链接并引导用户跳转。授权地址格式如下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
其中redirect_uri需要经过urlencode处理,state可以用于携带业务参数或防CSRF校验。注意末尾的#wechat_redirect必须保留,且必须放在#前使用&拼接参数。跳转后用户看到授权确认页,点击同意,微信会携带code和state重定向回你配置的回调地址。
第二步,用code换取网页授权access_token。code是一次性凭证,有效期只有5分钟,且只能消费一次,务必在回调处理中立即使用。接口调用示例如下:
<?php
$code = $_GET['code'];
$appid = '你的AppID';
$secret = '你的AppSecret';
// 用code换取网页授权access_token和openid
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?" .
"appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
$res = json_decode(file_get_contents($url), true);
if (isset($res['errcode'])) {
// 常见错误:40029 code无效,40163 code已被使用
exit('授权失败:' . $res['errmsg']);
}
$access_token = $res['access_token'];
$openid = $res['openid'];
$refreshToken = $res['refresh_token']; // 建议入库保存第三步,拉取用户信息。拿到access_token和openid后,调用userinfo接口即可获取详细资料:
<?php
$infoUrl = "https://api.weixin.qq.com/sns/userinfo?" .
"access_token={$access_token}&openid={$openid}&lang=zh_CN";
$userInfo = json_decode(file_get_contents($infoUrl), true);
// 返回字段:openid、nickname、sex、province、city、headimgurl等
// snsapi_base模式下调用此接口会返回errcode 10005
var_dump($userInfo);第四步,关于access_token的刷新。网页授权access_token有效期约2小时,refresh_token有效期30天。refresh_token在30天内可以重复使用刷新,刷新后会获得新的access_token和新的refresh_token。如果用户授权超过30天,则需要重新走一遍授权流程。因此建议把openid、access_token、refresh_token以及过期时间一起存入数据库,避免频繁要求用户重新授权。
三、升级改造的代码策略与降级容错
直接把代码里的scope常量改掉是最简单的做法,但更稳妥的方案是设计一个兼容两种模式的授权入口。对于已授权过的老用户,可以先尝试用缓存中的用户资料判断是否已授权userinfo;对于未授权的用户,再跳转snsapi_userinfo授权链接,这样能减少不必要的弹窗打扰。
改造时的参考实现:
<?php
function buildAuthUrl($appid, $redirectUri, $scope, $state = 'state')
{
$encodedUri = urlencode($redirectUri);
$scope = in_array($scope, ['snsapi_base', 'snsapi_userinfo']) ? $scope : 'snsapi_base';
return "https://open.weixin.qq.com/connect/oauth2/authorize" .
"?appid={$appid}&redirect_uri={$encodedUri}" .
"&response_type=code&scope={$scope}&state={$state}#wechat_redirect";
}
// 业务入口:先静默拿openid,再判断是否需要升级授权
$authUrl = buildAuthUrl($appid, 'https://你的域名/callback.php', 'snsapi_userinfo');
header('Location: ' . $authUrl);此外要做降级容错:如果用户在授权页点击拒绝,回调不会携带code而是携带auth_referer等参数,代码里要能识别并给用户友好的提示页面,而不是直接报错。同时,由于2021年底微信调整了用户信息接口策略,未关注公众号的用户即使授权成功,拉取到的昵称和头像也可能为空,业务上要有兜底处理,例如提供默认头像和默认昵称。
四、常见错误码排查清单
升级过程中最容易遇到的几个错误如下:
- 40029 invalid code:code无效或已过期,通常是本地调试时code被重复使用,或回调处理中code被消费了两次。
- 40163 code been used:code只能使用一次,检查是否存在页面刷新导致重复请求的问题。
- 10005 user not subscribe:用snsapi_base的access_token去调userinfo接口,必须升级scope后重新授权。
- 10003 redirect_uri域名与后台配置不一致:检查公众号后台网页授权域名配置,域名必须与redirect_uri的域名完全一致,且不需要加http协议头。
- 48001 api unauthorized:接口未授权,检查公众号类型,订阅号未认证时部分接口受限。
排查这类问题的通用方法是打印每一步接口的原始返回值,确认请求参数是否正确拼接。特别注意redirect_uri的urlencode只做一次,不要二次编码,否则微信会报重定向参数错误。
总体来说,从snsapi_base升级到snsapi_userinfo的核心工作在于:修改授权链接的scope参数、走完code换token的流程、调用userinfo接口拿资料,并把refresh_token持久化以便长期使用。配合合理的缓存与降级策略,升级改造可以在不影响老用户的情况下平滑完成。
微信公众号网页授权snsapi_userinfoOAuth2.0授权修改时间:2026-08-31 13:29:02