网站实现微信登录之回调函数中登录逻辑的处理--基于yii2开发的描述
上一篇文章网站实现微信登录之嵌入二维码中描述了如何在自己的登录页面内嵌入登录二维码,今天的这篇文章主要是描述下在扫码成功之后微信重定向回网站后登录逻辑的处理,其实也就是验证身份信息,授权用户登录的逻辑。这里说句题外话,写博客复习已经做过的项目真的有助于自己对已经写过代码和业务逻辑的理解,说不定还有意外的收获。所谓,“温故而知新”,我会保持写博客的习惯。
1,微信扫码成功之后
在用户扫码成功之后,pc端网站上的二维码会出现如下的提示:(这里是用的微信开发文档中的例子1号店网站用来演示效果)。
这里需要注意的是,微信开发文档中的例子请求登录1号店网站,它是给出了一个微信登录的链接https://passport.yhd.com/wechat/login.do,点击登录链接后会重定向到扫描二维码的页面,页面链接如下:https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=e25d9455e8f8e6f60a9fef0ba6509889#wechat_redirect,这个做法与上一篇文章网站实现微信登录之嵌入二维码的做法不同:它没有将二维码用js嵌入到登录页面login.do中,而是直接在登录页面中进行了重定向:
header('Location: https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect');
在实际开发中,应该根据设计的要求或客户需求来选择利用js嵌入还是在页面中重定向的方法。
然后,在手机端的微信中会弹出提示用户确认登陆1号店的界面:
点击登录按钮后,pc端网页会跳转到哪儿去呢?这个也要根据实际的业务逻辑来处理。
2,获取access_token和授权用户的openid
在redirect_uri的URL映射的对应的action中来通过code获取access_token。
1 public function actionCallback($code, $state) 2 { 3 // 获取并校验前台存储的随机串,防csrf攻击 4 $session = Yii::$app->session; 5 if ($state != $session->get('wx_state')) { 6 exit(); 7 } 8 $session->remove('wx_state'); 9 10 // 微信开放平台网站应用的appid和秘钥secret 11 $appid = 'appid'; 12 $secret = 'secret'; 13 14 $curl = new Curl(); 15 $wxresponse = $curl->get('https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid 16 . '&secret=' . $secret . '&code=' . $code . '&grant_type=authorization_code'); 17 $wxresult = json_decode($wxresponse);
注意:上面代码第14行用到了一个yii2的curl扩展,感兴趣的可以去github上看下。
第15行请求成功后返回的参数如下:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
参数 说明 access_token 接口调用凭证 expires_in access_token接口调用凭证超时时间,单位(秒) refresh_token 用户刷新access_token openid 授权用户唯一标识 scope 用户授权的作用域,使用逗号(,)分隔
actionCallback方法的参数中,$code是用户扫码确认登录后微信返回的,$state是自己设置的参数,详细可见网站实现微信登录之嵌入二维码一文。请求得到access_token和openid最后被存储到$wxresult中。
这里需要注意下,此处返回的openid与第3节中返回的openid是不同的,注意看参数说明。
3,利用上面获取的token和openid获取用户的个人信息,查询数据库验证登录。成功则设置session,不成功(新用户),可以考虑添加新用户实现扫码注册的逻辑。
1 if (isset($wxresult->errcode) && $wxresult->errcode > 0) { 2 // 向微信请求授权时出错,打印错误码 3 echo json_encode($wxresult); 4 exit; 5 } else { 6 // 获取用户个人信息(unionid) 7 $response = $curl->get('https://api.weixin.qq.com/sns/userinfo?access_token=' . $wxresult->access_token 8 . '&openid=' . $wxresult->openid); 9 $result = json_decode($response); 10 $wxUser = WxUser::find()->where(['wx_unionid' => $result->unionid])->one(); 11 if ($wxUser) { 12 // 登录 13 $result = Yii::$app->user->login($wxUser->id, 3600 * 24 * 30); 14 if ($result) { 15 // 登录成功,设置session 16 Yii::$app->session['wxuser'] = $wxUser->id; 17 } else { 18 // 登录失败 19 echo 'login 失败'; 20 exit(); 21 } 22 } else { 23 // 创建新用户 24 } 25 }
第7行请求成功后,返回的参数示例如下:
{ "openid":"OPENID", "nickname":"NICKNAME", "sex":1, "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" }
参数 说明 openid 普通用户的标识,对当前开发者帐号唯一 nickname 普通用户昵称 sex 普通用户性别,1为男性,2为女性 province 普通用户个人资料填写的省份 city 普通用户个人资料填写的城市 country 国家,如中国为CN headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 privilege 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。
上面代码第10行是依据用户的unionid是否在数据库中来验证其是否为网站的可登录用户,这里为什么要使用用户的unionid呢?这里涉及到了微信授权接口的UnionID机制。
微信开发文档授权后接口调用(UnionID)中对于unionid的解释:此接口用于获取用户个人信息。开发者可通过OpenID来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
我的理解是,每个用户对各公众号的OpenID是唯一的,而对于不同公众号,同一用户的openid是不同的。那么如果有多个公众号(服务号、订阅号),用openid就不能区分用户的唯一身份,就只能用unionid了。就算只有一个公众号,也建议采用unionid来区分用户身份的唯一性。
4,小结
微信扫码登录或注册方便了用户,但却增加了开发者的开发、调试等工作量。其实不止是开发阶段的工作量,整个网站在设计时就要考虑到这个功能,登录界面的设计、页面的跳转等。
参考:
完