微信的网页授权指的是在微信公众号中访问第三方网页时获取用户地理、个人等信息的权限。对于开发了自己的网页app应用时,获取个人的信息非常重要。上篇博客讲到了注册时可以获取用户的信息,很多人会问为什么还需要网页授权这种方式去获取呢,直接从数据库中读取不就可以了吗?这样的做的原因是服务器会话时间终究是有限的,关注后我们设置的会话一般在半个月左右,半个月后就需要重新生成会话,而这时就需要网页授权的openid帮忙了。况且,用户的信息也是会刷新的,虽然这种情况很少发生,但是我们至少应该确保信息是有一定的更新机制的。综上所述,由于会话机制和更新机制,我们需要用到网页授权。网页授权机制比较繁琐,步骤颇多,开发者在开发之前需要仔细阅读开发文档,不然会走很多弯路,卤煮也是吃了这方面的亏。本篇文章就来谈一谈微信的网页授权过程。

access_token(1)更新机制

很多接口需要用到这个access_token(1),之所以在后面加个(1)是为了区分另外一个网页授权access_token(2),他们之间的概念是不一样的,这里讲普通的access_token(1)。access_token(1)是你调用其他接口的凭证,它是通过以下接口生成的:

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxxxxxx&secret=xxxxxxxxx

请求以上接口会给你返回一个access_toke(1), 它有个有效时间,为7200s,一旦过了这个时间,再去使用它会报错。因此,必须建立一个刷新机制。我的办法是在服务器启动的时候去生成一次token,把它存入数据库,然后建立一个定时器,每隔7200s就再次请求接口获取新的token存入数据库,这样可以保证服务器运行的阶段,数据库中的表最后一条记录的是最新的token。每次需要用到这个token时候就先去表中查最后一条记录。如果只是临时使用,完全可以手动在浏览器调用接口生成toke,或者用postman工具。

/*启动时 定时获取刷新微信的token 并且存入数据库*/
(function() {
request(config('wechat').refreshUrl, function(err, res, body) {
body = JSON.parse(body);
var accessSql = 'INSERT INTO `access_token` (token) VALUES ("' + body.access_token + '")';
Query.call(res, accessSql, function() {
setTimeout(arguments.callee, config('wechat').refreshTime * 1000);
});
});
})();

创建网页菜单

创建网页菜单使用如下接口:

 https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

需要注意,菜单创建的接口只支持post发送的格式,因此,你的接口必须发送post请求。由于菜单不是一个经常需要变动的东西,卤煮创建菜单使用的是人工手动的方式进行创建。用的是postman发送特定数据到接口创建菜单。

发送的数据如图所示,多级菜单只需要数据嵌套就好了。有个key值,我在上一篇文章中提到过,点击该菜单时发送的xml包中接收到这个值。

网页授权获取用户openid

由于在关注的时候我们已经获取到用户的openid和用户信息(见前一篇张),因此,需要只需要用户的会话结束,我们才需要中心获取openid来建立会话。获取openid第一步,会话过期后服务器后台跳转到下面地址

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

appid不解释,redirect_uri即重定向后回掉的地址,一般写自己后台的接口地址。response_type写”code“就好了,scope指的是是否需要显示一个需要用户确认的界面如下所示:

如果是不需要直接填写snsapi_base获取openid,需要用户确认则获取所有信息请填写snsapi_userinfo,我们这里只需要openid,其他信息都在关注的时候存到数据库里面了。最后一个写死来“wechat_redirect”。用户点击确认登录或者在不需要点击确认的情况下过个几秒钟,微信会将地址重定向到你填写的url上,并且附带了两个参数redirect_uri?code=CODE&state=STATE。code是你换取access_toke(2)的票据,state表述状态,不需要关注。在你的回掉接口里面获取到code,然后将code作为参数post或者get请求以下连接,获取access_token(2):

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

该请求会返回一段json数据,里面就包含了我们需要的openid。

{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

接下来,以此openid为凭据,调用以下接口获取用户最新的信息:

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

access_token指的是access_toke(2),openid是上面的获取的openid,lang指的是数据的语言。默认为中文。你会获得以下json数据:

将它们更新到原有的表中(视情况而定,如果你觉得用户不经常更改自己的信息可以设置更新时间一个月或者半年),然后建立新的会话,至此,一个网页授权过程就结束了。

access_token(2)更新机制

在网页授权的过程中,也会遇到access_token(2)过期的问题,因此,我们也必须为它建立一个刷新机制。(微信搞得真的是很麻烦)。

首先,在使用access_toke(2)之前,我们先验证这个toke是否有效,请求以下接口进行验证:

https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID

错误的时候会返回如下数据

{ "errcode":40003,"errmsg":"invalid openid"}

这时候,我们就需要刷新这个token了,以下是刷新的接口:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

这里有一个refresh_toke指的是你去请求access_token(2)的接口返回的数据中的一个值。grant_tyoe直接填写为”refresh_token“。这样就刷新了一个token(2)。该token只是在网页授权时使用,可以不需要储存在表中,临时使用即可。

代码实现

我在这里使用的是一个第三方开发的模块,来处理一整套的token维护流程,它叫wechat-oauth。使用起来比较方便,源码也很好调试,自己稍微改了改。后面会贴出github的地址来,这个系列有很多,包括自动回复,图文消息等,大家有兴趣自己下载使用。当然,不嫌麻烦可以自己写。

var user = req.session['user'] || req.query._user;
//未登录的情况或者登录失效 网页调试无需走微信通道
if (user === undefined && !config('app').webDebug) {
var wxconfig = config('wechat');
//使用模块
var client = new OAuth(wxconfig.appId, wxconfig.appSecret);
var url = client.getAuthorizeURL(config('app').url + wxconfig.callbackUrl, 'snsapi_userinfo');
//后台跳转
res.redirect(url);
return;
}
fn.call(null, req, res, next);

获取code然后发送请求获取opeind

var client = new OAuth(wxConfig.appId, wxConfig.appSecret);
//................
//获取微信返回的网页TOKEN 该接口为回掉接口
app.get('/login/getpagetokenkey', function(req, res, next) {
var code = req.query.code; //微信返回的code值,作为下一步的票券
//获取票券
client.getAccessToken(code, function(err, result) {
var openid = result.data.openid;
//查询数据库有没有该用户
var sql = 'SELECT * FROM `wechat` WHERE openid= "' + openid + '"';
Query.call(res, sql, function(err, rows, filed) {
if(rows.length) {
//重新建立会话跳转到主界面
setSession(openid, res, req);
} });
});
return;
});

注意

在获取用户信息的时候的时候千万不要调试断点nodejs,因为微信会在发送给你的接口后设置一个等待时限,大概是6s,一旦过了这时限没有返回数据,而此时你如果在调试代码的话,很容易就会超过等待时间,接着微信就会再次发送一次请求给你的接口,这样会导致程序报错或者至少让你处理两次信息。卤煮吃了大亏,调了一个下午,接近奔溃的边缘。希望诸位要牢记此点,切记在获取授权的时候不要调试nodejs。

参考资料

wechat-oauth NodeJS开发微信交互模块

微信公众号开发官方文档

NodeJs 开发微信公众号(四)微信网页授权的更多相关文章

  1. 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结

    最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...

  2. C#版微信公众号支付|微信H5支付|微信扫码支付问题汇总及解决方案总结

    最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存.代码在文章结尾处,有需要的 ...

  3. JAVA版开源微信管家—JeeWx捷微3.2版本发布,支持微信公众号,微信企业号,支付窗、小程序

    JeeWx捷微3.2微信企业号升级版本发布^_^ JeeWx捷微V3.2——多触点管理平台(支持微信公众号,微信企业号,支付窗.小程序)   JeeWx捷微V3.2.0版本引入了更多新特性,支持微信公 ...

  4. JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗——JAVA版开源微信管家

    支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1——多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗)   JeeWx捷微V3.1.0版本紧跟微信小程序更新,在 ...

  5. JAVA版开源微信管家—JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗

    支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1--多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗) JeeWx捷微V3.1.0版本紧跟微信小程序更新,在原有 ...

  6. JAVA开源微信管家平台——JeeWx捷微V3.3版本发布(支持微信公众号,微信企业号,支付窗)

    JeeWx捷微V3.3版本紧跟微信小程序更新,在原有多触点版本基础上,引入了更多的新亮点:支持微信公众号.微信企业号.支付宝服务窗等多触点开发:采用微服务框架实现,可插拔可集成,轻量级开发:对小程序的 ...

  7. CabloyJS的微信API对接模块:当前支持微信公众号和微信小程序

    Cabloy-微信是什么 Cabloy-微信是基于CabloyJS全栈业务开发框架开发的微信接口模块,当前整合了微信公众号和微信小程序的接口,达到开箱即用的使用效果.在Cabloy-微信的基础上,可以 ...

  8. 微信公众号开发(5)---使用开源组件开发公众号OAuth2.0网页授权授权登录

    搞清微信公众号授权登录的步骤步骤,我们的开发就完成了一大步 献上github 地址: https://github.com/Wechat-Group/weixin-java-tools/wiki/MP ...

  9. 14-网页,网站,微信公众号基础入门(网页版MQTT,小试牛刀)

    https://www.cnblogs.com/yangfengwu/p/11192639.html 抱歉哈...最近由于做板子,,教程的进度落下了... 这些天总共做了还几块板子 首先对当前这个教程 ...

  10. 微信公众号支付JSAPI网页,total_fee错误不正确,header重定向参数丢失,无法获取订单号和金额解决

    微信公众号支付官方demo错误, 公众号支付只能用在微信里,也就是微信内部浏览器. 1.到WxPayHubHelper.php文件 JsApi_pub()类下createOauthUrlForCode ...

随机推荐

  1. 解决 Springboot Unable to build Hibernate SessionFactory @Column命名不起作用

    问题: Springboot启动报错: Caused by: org.springframework.beans.factory.BeanCreationException: Error creati ...

  2. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示(补充)

    在2.1.栏目的前台显示中因右键没有添加视图把微软给鄙视了一下,后来有仔细研究了一下发现应该鄙视自己,其实这个功能是有的,是自己没搞清楚乱吐糟. 其实只要在NuGet中安装两个包(Microsoft. ...

  3. tomcat开发远程调试端口以及利用eclipse进行远程调试

    一.tomcat开发远程调试端口 方法1 WIN系统 在catalina.bat里:  SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compi ...

  4. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  5. App 审核由于 IPv6 网络问题被拒

    昨天 提交App Store 的时候被拒了 We discovered one or more bugs in your app when reviewed on iPhone running iOS ...

  6. 解决 Could not find com.android.tools.build:gradle 问题

    今天拉同事最新的代码,编译时老是报如下错误: Error:Could not find com.android.tools.build:gradle:2.2.0.Searched in the fol ...

  7. 【Star CCM+实例】开发一个简单的计算流程.md

    流程开发在CAE过程中处于非常重要的地位. 主要的作用可能包括: 将一些经过验证的模型隐藏在流程中,提高仿真的可靠性 将流程封装成更友好的界面,降低软件的学习周期 流程开发实际上需要做非常多的工作,尤 ...

  8. 《Note --- Unreal 4 --- Sample analyze --- StrategyGame(continue...)》

    ---------------------------------------------------------------------------------------------------- ...

  9. Xamarin开发Android应用打包apk

    Visual Studio中用Xamarin开发Android应用,生成apk文件有3种方法 1.debug时,代码目录下bin\Debug中会自动生成调试用***-Signed.apk文件,但是文件 ...

  10. Memcached简介

    在Web服务开发中,服务端缓存是服务实现中所常常采用的一种提高服务性能的方法.其通过记录某部分计算结果来尝试避免再次执行得到该结果所需要的复杂计算,从而提高了服务的运行效率. 除了能够提高服务的运行效 ...