网站应用绑定微信
场景:
对于企业,可能会有产品线通常有网站,app,微信公众号等。统一各产品线的账号体系,实现一个账号处处使用的目标是非常有必要的。现在很多网站都已经建立了一套完整的用户账号体系,基于这套体系,很多功能得已实现,最近我帮公司实现了微信绑定的功能,现将心得以及挖过的坑记录下来。主要的效果是,网站本来是有一套账户体系,是将用户的手机号作为核心,但是现在有一个需求,就是用户在网站上的操作,本来是有短信提醒,但是为了以后预算以及小程序功能的扩展,现需要将网站和公众号之间通过微信来建立关系,通过公众号来进行推送消息。
请注意!!!:以下所有的操作必须将你需要绑定的公众号或者网站,都绑定在微信开放平台(https://open.weixin.qq.com/)上,进入下图中进行绑定
接下来我们就来讨论一下,如何做到微信公众号用户与网站用户的账号体系无缝对接。
首先在微信中有一个标识(OpenID),这个对于同一用户在同一公众号上是一样的,但是对于不同的公众号又是不一样的,那么由于用户在每个公众号上的OpenID都不一样,为了解决这个问题,微信为了标识同一个微信号,UnionID机制应运而生。UnionID对于一个用户在任何微信下面的应用都是相同的,这是我们解决问题的关键
首先设计数据库表,下面由于目前我主要是绑定网站和公众号,所以要保存两个openid,以及一个unionid(图中是wechatid)
设计完后,我们可以开始撸代码了,参考微信开放平台文档,我们将进行如下步骤
(1)准备工作
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
(2)授权流程
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
简而言之,就是先要有账号,然后根据自己的账号跳转去调用微信的页面(A),用户确认授权登陆后,微信的页面(A)会跳转到B接口,也就上面链接的REDIRECT_URI,在REDIRECT_URI中我们可以得到code,再请求access_token,利用这个access_token就可以获取用户的信息
这里要注意的是,
1.REDIRECT_URI必须编码,我这里使用了encodeURIComponent,
2.state是一个参数,等下微信回调接口的时候会带上这个参数,我这里将用户的id放进去,以便在下一个接口里面可以识别操作的用户
好,废话不多说,直接上图
第一步:获取code代码实现:
用户点击自己微信登陆或微信绑定的时候,让用户跳转到下面页面
微信授权页面示例用户在手机上经过授权,就会自动跳转到你上面链接中notify_url所指的接口,如下
回调接口如下:
notify_url?code=CODE&state=3d6be0a4035d839573b04816624a415e
当然,为了能够得到微信那边的信息,在进入notify_url接口时,就可以得到code。当然我们最终的目的是要得到用户的信息,code只是一个中间量,根据code,获取access_token,如下链接
返回结果如下
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
获得了access_token以及openid后,就可以来调用用户信息,如下链接
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
返回结果如下
{
"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"
}
这里很轻松拿到了用户信息,以及最重要的unionid
第二,三步代码如下:
这里用到了一个很好的node模块request,在使用前请先安装
var request=require('request')
router.get('/weiChartBindQrForTwo',function(req, res, next) {
if(req.query.code){
var userId=req.query.state
var url='https://api.weixin.qq.com/sns/oauth2/access_token?appid='+settings.appid+'&secret='+settings.secret+'&code='+req.query.code+'&grant_type=authorization_code'
request.get({
url:url
},function(error, response, body) {
if(response.statusCode==200) {
var callBackObj=JSON.parse(body)
console.log(callBackObj)
if(callBackObj.openid) {
User.findOne({wechatId:callBackObj.openid},function(err, u) {
if(_.isEmpty(u)) {
WxCheck.findOne({wechatId:callBackObj.unionid},function(err, wxcheck) {
if(_.isEmpty(wxcheck)) {
User.findOneAndUpdate({_id:userId}, {
$set: {
wechatBind:true,aOpenId:callBackObj.openid,
wechatId:callBackObj.unionid
}
},function(err, user) {
res.redirect('/users/qqweichartBinding?weiChatBind')
})
}else{
User.findOneAndUpdate({_id:userId}, {
$set: {
wechatBind:true,aOpenId:callBackObj.openid,
wechatId:callBackObj.unionid,bOpenId: wxcheck.openId
}
},function(err, user) {
res.redirect('/users/qqweichartBinding?weiChatBind')
})
}
})
}else{
res.redirect('/users/qqweichartBinding?weiChatBindSame')
}
})
}
}else{
console.log(response.statusCode);
}
})
}else{
res.redirect('/users/home')
}
})
细心的童鞋已经发现了,这里买不光光只有获取unionid那么简单,这其中涉及到后面的问题,也就是,微信公众号与网站数据库绑定的问题。
现在有这样两个场景:
一、用户绑定成为我们的网站用户,但还未关注我们的微信公众号;
二、用户未绑定成为我们的网站用户,但已关注我们的微信公众号。
正是存在这个问题,在微信绑定的时候,也会往WxCheck这个表里面写入unionid以及微信公众号的openid,未避免冲突,先查找是否绑定微信(即WxCheck去查找unionid),绑定了,直接往user写入各自openid以及unionid,如果没有绑定,将unionid以及网站openid直接写入user。
好,到目前为止,网站绑定微信已经完成,这两天我会继续发布微信公众号的文章
如有任何问题,欢迎跟我交流!
网友评论