微信公众号在获取用户信息的时候,一般用到下面写法:
$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$wx_access_token}&openid={$wx_open_id}";
$wx_info = FHttp::get($url);
$wx_info = json_decode($wx_info, true);
$data = [
'openid' => $info['openid'],
];
if ($wx_info) {
$data['nickname'] = $wx_info['nickname'];
$data['sex'] = $wx_info['sex'];
$data['language'] = $wx_info['language'];
$data['city'] = $wx_info['city'];
$data['province'] = $wx_info['province'];
$data['headimgurl'] = $wx_info['headimgurl'];
}
$wx_id = FDB::insert('wx_info', $data);
当然在进行这一步之前,必须获取接口必要参数:access_token
,而关于获取用户这个参数的地方,就有意思了,微信提供了2个方式:
public function getOauthBaseUrl($callback, $state = '')
{
if (!$state) {
$state = md5(uniqid(rand(), true));
}
$callback = urlencode($callback);
FSession::set('state', $state);
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$callback}&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect";
}
public function getOauthUserInfoUrl($callback, $state = '')
{
if (!$state) {
$state = md5(uniqid(rand(), true));
}
$callback = urlencode($callback);
FSession::set('state', $state);
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$callback}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
}
之所以写2个函数,也是为了方便调用,其实这2个函数中,唯一不同的地方就在与接口的一个参数不一样:scope
,一个是snsapi_base
,一个是snsapi_userinfo
,那么我就是这么掉进坑里去的。
开始,我呢,用的是 snsapi_userinfo
,当然是为了获取用户的头像和昵称。
那么,客户找我商量,现在打算给其他局的一个所里做一下试点,但他那边没有公众号,于是打算接入到我局里,有一个小问题就是每次采集用户微信头像时候,就弹出一个我局的公众号让点允许,这个能不能去掉一下。
我想了一下,记得还有一个snsapi_base
接口,做了一下测试,发现同样可以获取到用户头像,于是,拍着胸脯说,修改好了。
然后,上线,然后,就掉坑里了
新用户登陆后,没有头像,没有昵称
在获取用户信息接口的地方,打了一下log,通过观察,返回了 48001 错误:
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: YGabOOXIRa-djGckA ]"}
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: YGabBbwgE-p0U4cA ]"}
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: zGabA3LnRa-n8clKa ]"}
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: zGabt24ce-FEx4Da ]"}
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: zGabuAwgE-PhQmMA ]"}
{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: zGabY24ce-aO4OGa ]"}
这就奇怪,我赶紧拿出我的手机,扫了一下码,却发现接口返回正常,拿了同事的手机也是正常,可是采集上来的数据,就很奇怪了。很多 api unauthorized
于是找原因。。。
于是把接口改回到 snsapi_userinfo
,写了个 demo,单独调用这几个接口测试,发现换来换去并没有什么不同。都可以获取接口参数。
来来回回不知所踪了。
就在这时,打扫卫生的小姐姐路过。
“小姐姐,接手机用一下呗,测试一下程序。”
小姐姐瞟了一眼,嫣然一笑,“借口~”
“啥接口?哦哦,对对对,我就是测试一下接口”
小姐姐貌似很无奈,”我微信就是我手机号,185xxxx“
“额。。。不行啊,我必须扫码呀。”
“我连手机号都告诉你了,你还想干啥”
“我真的是借来的测试用的!”
小姐姐一脸怀疑拿出手机递给我。
奇迹就这么出现了。小姐姐的手机扫码,就报了这个错!
我去,啥情况啊,不会微信知道我们是搞程序,同样的接口,程序员的手机能获取,不是程序员就不能获取吧,这也太 AI 了吧。
抱着试试看看的态度,把接口换成了 userinfo,理所当然的,通过接口获得了小姐姐微信信息。
看来这个userinfo接口是没问题了。问题就处在base上,于是,换上base再测试。。。
奇迹又出现了,同样的base接口,之前不能返回信息,现在也能返回信息了。
一天两次奇迹,虽然是程序猿的脑袋也经不起这么大惊喜啊。
纵我试她千百遍,依然待我如初恋。
base接口获得的 access token,也同样能获取用户微信信息了。
冷静下来,仔细想想。我要静静。。。。
会不会是因为走过了一次userinfo,就给微信开了绿色通道了呢。
为了认证这一想法,又搞到了几部手机,先base,再 userinfo,再base。
一圈走下来,证实了我的想法。
用户必须要先走一次 userinfo , 用户在手机上同意了获取用户信息,之后便暂时开启了绿色通道。
所以当你用base也能获取的时候,不要大意,因为。。。这是一个坑,你能,并不代表其他的广大老百姓也都能。
总结
- 使用
scope=snsapi_userinfo
,用户微信点击同意,才能获取到用户的基本信息 - 没有点过同意,使用
scope=snsapi_base
,并不能获取用户信息,但能得到openid,可以根据这个进行微信登陆 - 用户点过同意后,再一次使用无论是
scope=snsapi_base
还是scope=snsapi_userinfo
都能获取用户的基本信息
当然感觉上用 scope=snsapi_base
还是不保险,虽然能获取用户信息,不知道是暂时的,还是永久的。想要获取用户基本信息,尽量全都用 scope=snsapi_userinfo
吧。