相信不少人接触过微信公众号的开发,最近我刚做完一个微信公众号开发的项目,也是本人经手的第三个微信公众号项目,对于微信公众号开发也算是有些许经验,打算在这里总结一下,主要分为两块来讲:网页开发和后端开发。
首先介绍一下微信公众号的种类,微信公众号分为服务号和订阅号(其实还有企业号,但是企业号我没有玩过,所以这里就不说了)。两者区别很大:首先是两者在微信中出现的位置不同,订阅号出现在专门的订阅号单独二级入口里,而公众号则出现在微信主页上;相对的,两者触达用户的能力也是有很大差别的,服务号每个月只能给用户群发4次消息,而订阅号每天都可以向用户推送一条消息,由此可见,微信将订阅号放在单独的二级入口里也是很有必要的,否则谁受得了每天那么多条新消息出现在自己的微信首页上;两者的接口权限也有很大的区别,具体可见官方文档,简而言之,如果是要做微信开发,要获取到微信用户信息,那基本上必须要用服务号来做,如果要接微信支付,则还需要将服务号认证。
微信开发主要分为两大块,网页开发及后台开发。本文主要介绍一下网页开发。什么是微信网页开发?简单说来就是开发一个在微信浏览器中使用的网页,当然,我要讲的不只是一个普通的H5页面,而是需要获取到微信用户信息的网页应用。如果想要在页面中获取到用户信息,那么就需要微信用户的网页授权,获取微信用户的网页授权分为一下几步:
- 先准备一个服务号,因为只有服务号才有微信网页授权的接口权限。并且在公众号设置-功能设置里配置网页授权域名。注意,这个网页授权域名必须和需要获取用户网页授权的页面的域名相同。这里假设网页授权域名为www.sawyer.com。
- 引导用户点击微信授权链接,微信授权链接的格式为: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
针对这个请求的参数进行一下解释:
-
appid
就是你申请的服务号的appid,可以在公众号基本配置中查看。 -
redirect_uri
代表授权成功后回调的地址,域名必须和步骤1中填写的网页授权域名一致,比如要回调的页面uri是/home,那么回调地址应为http://www.sawyer.com/home,并且不能带端口。注意,REDIRECT_URI的值需要进行urlEncode处理; -
response_type
填写code即可。 -
scope
代表授权类型,有基本级别snsapi_base
以及用户信息级别snsapi_userinfo
。如果是base级别,对于用户来说是无感知的静默授权,但是能获取到的也只有用户的openid而已,如果是userinfo级别,那么对于已经关注公众号的用户来说也是静默授权,但是对于没有关注公众号的用户,则需要用户手动点击授权页面,如下。
-
state
是用户自定义参数,回调时会原封不动传回来。可不填。
注意,微信会对请求网页授权接口的参数进行正则强匹配校验,所以请确保参数的顺序。如果授权成功,则微信会将请求重定向到REDIRECT_URI指定的地址,并且带上code和state两个参数。
- 使用上一步返回的票据code去微信服务器换取网页授权基础信息,其中包括网页授权access_token。注意,这里的网页授权access_token和下一篇的基础服务access_token不同。请求地址为:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
针对这个请求的参数进行一下解释:
-
appid
就是你申请的服务号的appid,可以在公众号基本配置中查看。 -
secret
就是你申请的服务号的appsecret,可以在公众号基本配置中查看。 -
code
就是上一步返回的code,是微信用户网页授权的短期一次性票据,有效期5分钟。 -
grant_type
填写authorization_code即可。
注意,由于appsecret是公众号非常机密的信息,不允许在前端保存,所以这一步必须由后端实现。请求成功将会返回微信用户的网页授权基本信息:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
如果scope类型为snsapi_base
,那么微信网页授权到此结束,已经拿到微信用户的openid。注意,任意微信用户对于同一公众号有唯一openid,对于不同公众号有不同openid,所以开发者需要在多个微信公众号中鉴别同一个用户的话,需要用到unionid机制。要获取用户的unionid需要开发者的公众号绑定到微信开放平台后,使用snsapi_userinfo级别的网页授权才能获取,或者用户关注后使用微信用户管理接口获取用户详细信息,这个在下一篇中会介绍。
- 如果scope类型为
snsapi_userinfo
,那么可以使用上一步获得的网页授权access_token来请求微信接口获取用户详细信息。接口链接如下:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
针对这个请求的参数进行一下解释:
-
access_token
上一步获取到的网页授权access_token,网页授权access_token是一个长期令牌,有效期2小时,即上一步返回的expires_in的时间。如何刷新下一步会讲。 -
openid
上一步获取到的微信用户的openid。 -
lang
返回国家地区语言版本,zh_CN简体,zh_TW繁体,en英语。
请求成功的话,返回对象如下:
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl":"http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1", "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL",
"lang": "zh_CN"
}
注意,网页授权access_token作为机密信息,不允许保存在前端,该请求应由后端发起。到这一步已经取到了微信用户的详细信息,unionid是需要用户绑定公众号到微信开放平台后才会出现。这里要吐槽一下微信开发文档,其中有不少错误,比如这里的返回对象,官网的文档就少了"lang"这一项(2018/1/17)。
- 如果需要的话,使用步骤3获取的refresh_token请求以下链接刷新网页授权access_token:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN。
-
appid
公众号的appid。 -
grant_type
填写refresh_token。 -
refresh_token
步骤3获取到的refresh_token。
请求成功后返回对象和步骤3是一样的,就是微信网页授权基本信息。
上面介绍了一下微信网页授权的步骤,那么我们在代码中如何实现呢?下面我将基于前后端不分离的MVC架构和前后端分离的SPA架构具体讲一下代码实现的方式。刚好两种架构我都做过微信开发。
MVC
先上流程图,在这里安利一下ProcessOn这个在线画图工具,非常强大非常好用,大家有兴趣的点击此处注册喔~
稍微解释一下,WeChatOAuthFilter过滤器主要的作用是调用微信接口获取微信网页授权基本信息(步骤3),WeChatOAuthIntercepoter拦截器主要的作用是将请求地址封装到微信redirect_uri去微信服务器做网页授权(步骤2)。
过滤器首先过滤微信浏览器的请求,如果发现session中没有微信授权信息,那么就检查请求是否带有参数code和state,如果有,说明该请求是做完了微信网页授权的回调请求,那么就可以请求微信服务器拿code换取基础网页授权信息,同时将该信息放入session;如果没有则进入拦截器。如果拦截器发现session中没有授权信息,则将请求uri封装到微信redirect_uri,并且跳转到微信服务器去做网页授权,并且拦截此次请求(拦截器实现HandlerInterceptor,preHandle方法返回false)。
tips: 通过判断request header中的User-Agent属性是否含有micromessenger即可判断请求是否来自微信浏览器。
SPA
如果你使用的是Vue或者Angular这样的SPA框架,那么微信网页授权更加简单。先看一下架构图:
对于SPA来说,由于后端无法直接重定向,所以微信网页授权需要由前端实现,通过直接将url地址设置为微信网页授权的地址的方式,使得用户访问页面的时候已经完成了网页授权,既在SPA中已经拿到了用户的授权code。在进行ajax请求的时候带上code,过滤器使用code换取网页授权基本信息即可。
总结一下,对于微信网页授权来说,大多数情况只需要获取用户的openid,因为详细信息完全可以通过后台调用微信接口拉取,这个下一篇会介绍。所以一般scope使用snsapi_base
级别的即可。获取openid分为两步,第一步引导用户点击或者后端重定向到微信网页授权地址,用户静默授权,微信服务器回调redirect_uri,同时参数带回code。第二部使用code换取网页授权基本信息,包括openid及网页授权access_token。