微信的网页授权指的是在微信公众号中访问第三方网页时获取用户地理、个人等信息的权限。对于开发了自己的网页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. 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)

    上一节部署了 cirros-vm1 到 first_local_net,今天我们将再部署 cirros-vm2 到同一网络,并创建 second_local_net. 连接第二个 instance 到 ...

  2. JavaScript动画-碰撞检测

    ▓▓▓▓▓▓ 大致介绍 碰撞检测是指在页面中有多个元素时,拖拽一个元素会出现碰撞问题,碰撞检测是以模拟拖拽和磁性吸附中的范围限定为基础的 效果:碰撞检测 ▓▓▓▓▓▓ 碰撞检测 先来看看碰撞检测的原理 ...

  3. CSharpGL(33)使用uniform块来优化对uniform变量的读写

    CSharpGL(33)使用uniform块来优化对uniform变量的读写 +BIT祝威+悄悄在此留下版了个权的信息说: Uniform块 如果shader程序变得比较复杂,那么其中用到的unifo ...

  4. ASP.NET MVC原理

    仅此一文让你明白ASP.NET MVC原理   ASP.NET MVC由以下两个核心组成部分构成: 一个名为UrlRoutingModule的自定义HttpModule,用来解析Controller与 ...

  5. PHP设计模式(五)建造者模式(Builder For PHP)

    建造者模式:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示的设计模式. 设计场景: 有一个用户的UserInfo类,创建这个类,需要创建用户的姓名,年龄,爱好等信息,才能获得用 ...

  6. ABP领域层

    1.实体Entites 1.1 概念 实体是DDD(领域驱动设计)的核心概念之一. 实体是具有唯一标识的ID且存储在数据库总.实体通常被映射成数据库中的一个表. 在ABP中,实体继承自Entity类. ...

  7. Android游戏开发实践(1)之NDK与JNI开发03

    Android游戏开发实践(1)之NDK与JNI开发03 前面已经分享了两篇有关Android平台NDK与JNI开发相关的内容.以下列举前面两篇的链接地址,感兴趣的可以再回顾下.那么,这篇继续这个小专 ...

  8. ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)

    前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...

  9. redis大幅性能提升之使用管道(PipeLine)和批量(Batch)操作

    前段时间在做用户画像的时候,遇到了这样的一个问题,记录某一个商品的用户购买群,刚好这种需求就可以用到Redis中的Set,key作为productID,value 就是具体的customerid集合, ...

  10. /etc/ppp/chap-secrets

    # Secrets for authentication using CHAP # client server secret IP addresses abc l2tpd * client:VPN 用 ...