为什么80%的码农都做不了架构师?>>>   

需要解决的问题

微信的第三方开发者平台采用的是OAuth的认证流程。因此,需要解决的问题是:

  1. 按照OAuth的流程,调用微信第三方平台的api来获取pre_authenticatioin_code 等参数,提供授权页面让服务号管理者授权;

  2. 这里面,有7、8个参数需要通过微信API一步一步的获取。而且当中的某些参数是有过期时间的,因此,需要后端服务能够在过期前自动调用微信API重新获取,并保存这些参数;

  3. 考虑到要能够支持多家不同的维修服务号业务应用,因此需要schema设计上支持多个tenant;

  4. 需要考虑冷启动的问题。因为,这些参数缓存在memory里面(持久化存储是没有意义的,因为大部分参数过期失效),所以,需要考虑如何从DB 中load 部分参数(如何component access token)以及 快速重新发起微信参数请求;

  5. 这7、8个参数是有依赖关系的,用前一个获取后一个。因此,一旦网络连接失效,在获取前面的参数不能成功的情况下,需要重试,成功后,再接着下面的参数请求。

具体步骤

(因为这些代码还没有来得及放到 npm上,所以有需要代码的mail to fxfx_001@163.com. )

(一)得微信开资质及部署公众号用的步

这一步,网上已经有很多可以参考的资料。 无非就是去提供一个企业工商名称,提供一个银行卡号,然后花点钱,让微信给你开个账户。 之后,进入到微信第三方开发者平台,选择公众号第三方平台。

注释 : 只有处在白名单列表中的微信后台服务才能够接调用wechat 平台的api。因此,一般情况下,可以通过nginx的forward proxy 做后台微信的前置机,每次调用api的时候,传出的是这个nginx所在机器的ip地址。

另外,还需要注意的是,这里面所有涉及域名的部分最好保持一致。

(二)存储在wechat 通的数据schema

这个schema 中定义了wechat 通需要存储的服务号具体配置信息。

var wxaccountSchema = new Schema({

mdt_app_id:{type: String, unique:true},

wx_authorizer_apps : [{

wx_authorizer_app_id:{type:String,required:true},

wx_authorizer_refresh_token:{type:String,required:true},

wx_origin_menu_config: {type:String},

wx_mapped_menu_config: {type:String},

wx_mapped_menu_click : {type:String},

wx_authorizer_info:{type:String}

}]

});

mdt_app_id - 是指一个门店通应用的app_id ,这个app_id 是在应用管理平台上创建时,系统分配给这个品牌商企业的一个唯一标识;

一个app_id 其实可以指定多个应用服务号 (当然,还有一个大前提是,门店通应用需要在wechat 第三方开发者平台通过全网测试)

wx_authorizer_app_id - 是指授权给门店通(wechat 通)管理的服务号应用的id ,这个id 是wechat 平台为每个服务号应用指定的;

wx_authorizer_refresh_token - wechat 通第三方授权的流程最终目的就是要获得这个 refresh_token 以及 访问/替代服务号接受消息的access_token。这里的两个token 一个是存储在db 中(因为,只有通过这个token 才能获得 access-token) , 一个是存储在redis 缓存中;

wx_*_menu_config - 等参数是用于当wechat 通接管微信服务号时,获取现有服务号中的menu 配置信息,为了不造成对终端用户的影响,当你被授权接管服务号时(具体是因为,wechat 通需要获取消息管理权限,而这个权限间接需要自定义menu的权限),需要能够重新设定菜单的配置,这些配置需要存储下来;

wx-authorizer_info - 是一个string 类型,这里存储的是wechat 服务号授予的具体权限集等信息。

(三)wechat 通中各个token及授权码的自动刷新获取

每个微信服务号第三方应用在创建时需要获取 verify-ticket 以及 component_access_token 以及pre_auth_code , 这三个参数的获取顺序依次递进的,而且,每个code 都有过期时间,因此wechat 通需要make sure 这些参数在它过期前重新刷新并替换掉现有的。

而对于,wechat 通自己的应用配置信息,可以存储到db 中或者在应用启动时pass in 到配置文件里,

wechat_platform_config : {

appid: 'wx4ce1df4ef19c19ac',

appsecret: 'ee57d830c7885b90eaba9be18b30f9fa',

msg_token: '123456789mdt',

msg_aeskey: 'p0o9i8u7y6t5r4e3w2q1azsxdcfvgbhnjmkl0987654',

oauth_callback_url: 'http://wechat.mdt.goelia.com.cn/callback'

},

注: msg_token 及aeskey 等参数用于在收发wechat 平台的加解密信息时用于签名的验证。

1) 在wechat 通启动时,尝试获取verify-ticket 等参数 (verify-ticket ,每隔10分钟,wechat 平台会自动同步给应用端,获取后,再去获取component_access_token 及 pre_auth_code ,也可以看出这几个参数间的获取顺序)

function loadWxPlatformParams(){

logger.info('Load mdt-wechat platform params');

searchDependedParam(PLATFORM_TICKET_KEY)

.then(function(){

return redisClient.getAsync(PLATFORM_TICKET_KEY)

})

.then(function(param){

return wxplatform.getComponentAccessToken(param);

})

.then(function(rs){

return wxplatform.createPreAutCode(rs);

})

.then(function(){

return wxservice.findWxAccountsBymdtAppId('')

})

.then(function(rs){

if (rs instanceof Array && rs.length == 1){

rs[0].wx_authorizer_apps.forEach(function(o){

redisClient.getAsync(PLATFORM_TOKEN_KEY)

.then(function(token){

return wxplatform.refreshAuthorizerAccessToken(token, o.wx_authorizer_app_id, o.wx_authorizer_refresh_token);

})

.then(function(rs){

logger.info('After refresh AuthorizerAccessToken, returned authorizer_app_id is '+rs+'. Going to set WechatApi Instance');

//set wechat api instance

return wxplatform.setWechatApiInstance(rs);

2)存储在redis 中各个参数被设置了expire 时间,当expire 时间到了的时候,wechat 通会获取到对应的事件来触发重新刷新的过程

redisPubSub.on(REDIS_EXPIRE_EVENT, function(data, channel){

if (PLATFORM_TOKEN_KEY_SHADOW === data){

searchDependedParam(PLATFORM_TICKET_KEY).then(

function(param){

return wxplatform.getComponentAccessToken(param);

}

).then(function(rs){

logger.info('Trying to refresh component token - '+rs);

}).catch(function(err){

//retry....

});

} else if (PLATFORM_PRE_AUTH_CODE_KEY_SHADOW === data){

searchDependedParam(PLATFORM_TOKEN_KEY).then(function(param){

return wxplatform.createPreAutCode(param);

}).then(function(rs){

logger.info('Trying to refresh '+PLATFORM_PRE_AUTH_CODE_KEY+' - '+rs);

}).catch(function(err){

//retry....

});

} else if (_.endsWith(data,'authorizerAccessToken-shadow')){

var ds = _.split(data,':');

var authorizer_app_id = ds[1];

//TODO - PLATFORM_AUTHORIZER_ACCESS_REFRESH_TOKEN & PLATFORM_AUTHORIZER_APPID should be tried reading from DB firstly.

//TODO - If not there, check if the authorization_code expires. If not, go getting it. Otherwise, ask customer to re-do OAuth.

Q.all([searchDependedParam(PLATFORM_TOKEN_KEY),wxservice.findRefreshTokenByAuthAppId('',authorizer_app_id)])

.spread(function(token,refresh_token){

if (token && refresh_token && authorizer_app_id){

return wxplatform.refreshAuthorizerAccessToken(token,authorizer_app_id,refresh_token);

} else {

logger.info('refresh_token is '+refresh_token);

if (!refresh_token){

logger.info('refresh_token for authorizer_app_id '+authorizer_app_id+' is null!!');

}

}

}).then(function(rs){

logger.info('Trying to refresh Authorizer Access Token - '+rs);

return wxplatform.setWechatApiInstance(rs);

}).catch(function(err){

//retry....

logger.error(data+' is expired from redis. But error happened during refreshing authorizer access token.'+ u.inspect(err,false,null));

});

}

});

3)  wechat 通生成让服务号管理员登陆授权的页面。其中的点击登陆授权link 是wechat 平台要求提供的。

其中可以看见,redirect_url 是wechat 通自己制定的auth_call_back url 链接。

exports.getOAuthPage = function(req, res) {

//Obtain the pre_code only exists

redisClient.getAsync(PLATFORM_PRE_AUTH_CODE_KEY)

.then(function(value) {

if (value) {

var strUrl = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=' + config.wechat_platform_config.appid + '&pre_auth_code=' + value + '&redirect_uri=' + encodeURIComponent(config.wechat_platform_config.oauth_callback_url);

//var header = '';

//var body = '<a href=\"' + url+ '\" id=\"authurl\" style=\"display: inline;\">' + 'click here to authorize!!!</a>';

//var html = '<!DOCTYPE html>'

//    + '<html><header>' + header + '</header><body>' + body + '</body></html>';

res.render('oauth', { oauth_url: strUrl });

} else {

res.status(404).end();

}

});

};

3) 服务号授权后,wechat 通需要保存各项menu config 以及获取access_token 以及refresh-token.

注: 这里的authCallback 是wechat 开放平台的OAuth2.0 协议的一个实现,即,你传入一个auth_callback 的url, 一旦服务号的管理员授权后,wechat 将authorization code 通过这个call back url 回传给wechat 通。 wechat 通,接下来可以用这个authorization-code 接着获取access_token.

exports.authCallback = function(req, res) {

var authorization_code = req.query.auth_code;

var expire = req.query.expires_in;

logger.debug('Authorization code is ' + authorization_code);

//redisClient.set(PLATFORM_AUTH_CODE, authorization_code);

//If the auth_code expires, it can only be obtained by asking cutomer re-do oauth.

//redisClient.expire(PLATFORM_AUTH_CODE,expire);

res.status(200).send("success");

//Authorization code will expire. So, it is possible to get the access_token & refresh_token asap.

//And by wechat specification, authorization code can only be obtained when doing the OAuth.

//So before expire, the authorizer_access_token can be obtained for multi-times.

_getAuthorizerAccessToken(authorization_code)

.then(function(rs) {

//TODO - Set the mdtAppId formally

//set wx_app_id and wx_refresh_token to database.

return wxservice.createWxAccount('', { "wx_authorizer_app_id": rs.authorizer_appid, "wx_authorizer_refresh_token": rs.authorizer_refresh_token });

})

.then(function(rs) {

//Note- Then save it to redis as well.

redisClient.set(u.format(PLATFORM_AUTHORIZER_ACCESS_REFRESH_TOKEN, rs.wx_authorizer_app_id), rs.wx_authorizer_refresh_token);

return _obtainWxAccountDetailInfoAndSave(rs.wx_authorizer_app_id);

}).then(function(rs) {

return _setWechatApiInstance(rs.authorizer_app_id);

}).then(function(rs) {

//generate menu config

return _convertMenus(rs.authorizerAppId);

}).then(function(rs) {

//save to db for menu config

//Hardcode the mdtAppId

return wxservice.updateWxAccountMenuConfig('', rs);

}).then(function(rs) {

//create menu

return _createWxAccountMenu(rs);

4)获取refresh_token 及access-token 后创建应用(app_id)对于的wechat api instance。 这个instance主要用于操作服务号中的各种api (如,模板消息api,客服接口消息api,素材管理api 等)

function _setWechatApiInstance(authorizer_app_id) {

var deferred = Q.defer();

redisClient.getAsync(u.format(PLATFORM_AUTHORIZER_ACCESS_TOKEN, authorizer_app_id))

.then(function(authorizer_access_token) {

if (authorizer_app_id && authorizer_access_token) {

var api = new WechatAPI(authorizer_app_id, "", function(callback) {

//Make sure the token is refreshed before the expire time. So, for wechat-api, just set the expire time for a

//far time

var ts = new Date('2016-12-30 23:59').getTime();

callback(null, { "accessToken": authorizer_access_token, "expireTime": ts });

});

apiWechatMap.set(authorizer_app_id, api);

deferred.resolve({ 'authorizerAppId': authorizer_app_id });

} else {

deferred.reject(new Error('No token value'), {});

}

});

return deferred.promise;

转载于:https://my.oschina.net/geofx/blog/664054

基于NodeJs的微信第三方平台认证授权流程相关推荐

  1. 微信第三方平台之授权流程(三)

    注:这篇文章基础是小程序已创建成功(不懂得看我前面的文章) 授权流程技术说明 小程序或者公众号授权给第三方平台的技术实现流程比较简单,如下图所示: 第三方服务商构建授权链接放置自己的网站,用户点击后, ...

  2. 微信第三方平台公众号授权流程1—第三方平台概述概述

    一.概述 公众平台第三方平台是为了让公众号或小程序运营者,在面向垂直行业需求时,可以一键授权给第三方平台(并且可以同时授权给多家第三方),通过第三方平台来完成业务,开放给所有通过开发者资质认证后的开发 ...

  3. 微信第三方平台授权流程- java

    1. 微信第三方平台的开发,第一步就是公众号的授权,授权成功后第三方凭条才能利用公众号的appid和token获得公众账号额信息,并代替公众账号完成一些功能. 2. 授权的流程,理论图 代码流程, 1 ...

  4. 用微信第三方平台授权小程序业务

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 本文章转自php中文网:http://www.php.cn/weixin-kaifa-4069 ...

  5. 微信第三方平台-授权流程经验分享

    原文地址: www.jianshu.com/p/67836ffa9- 在做微信第三方平台开发的时候,虽然授权的技术实现流程比较简单,但是相对于一个key直接集成的一些其他的服务来说,还是有一些步骤,过 ...

  6. 微信第三方平台授权时域名问题

    最近在处理微信第三方平台的问题,在授权的时候总是提示"请确认授权入口页所在域名,与授权后回调页所在域名相同,并且,此两者都必须与申请第三方平台时填写的授权发起页域名相同." 如提示 ...

  7. 微信公众号通过第三方平台完成授权

    微信公众号通过第三方平台完成授权前,第三方平台与公众号绑定关系. 为什么要使用第三方平台来完成授权,公众号本身授权也可以,但是微信平台会认为你具有开发能力,免费提供给你的自定义菜单以及其他功能将不能再 ...

  8. 微信公众平台如何授权第三方平台,干货到!微信公众号怎样添加第三方平台及取消授权

    微信公众号是我们经常使用的行业资讯平台,通过公众号我们可以更有效的传播我们的服务信息.提供更改的服务水平.效率.有时候我们需要授权第三方平台来进行操作会更加方便,那么如何在微信公众平台授权第三方平台呢 ...

  9. 关于微信第三方平台授权61004:access clientip is not registered requestIP

    关于微信第三方平台授权61004:access clientip is not registered requestIP 这个问题让我难受了2个小时,最后总结下问题: IP白名单 授权的服务器一定要添 ...

最新文章

  1. MySQL设值自动修改时间
  2. Bootstrap3 表格-带边框的表格
  3. HTML字体小于12谷歌不兼容,Chrome谷歌浏览器下不支持css字体小于12px的解决办法【原创】...
  4. java事件编程_java基础 ---Swing事件编程
  5. mysql执行过程五步_简单五步教你搭建MySQL主从复制
  6. SuperSet连接Hive失败(客户端报日志拒绝连接)
  7. XML/YAML文件的输入输出
  8. OO4O的session残留问题
  9. (二)Graphivz 简单结构图及子图
  10. [转载] Python导出Excel图表
  11. python2.7安装教程win7_win7下python2.7安装 pip,setuptools的正确方法
  12. 一次全链路压测-总结
  13. 计算机组装故障排除方法,计算机的硬件组装及故障排除
  14. c语言设计一个酒店管理系统,C语言酒店管理系统设计.docx
  15. vs2019新手怎么解决命名空间“”中不存在类型或命名空间名“”(是否缺少程序集引用?)问题全解
  16. 智安网络丨德勤发布2021九大技术趋势,零信任安全成为主流
  17. java 分层处理解耦_后端分层架构如何解耦?
  18. 自控力读书笔记 第八章 传染:为什么意志力会传染?
  19. 如何将SNS光纤交换机(OEM博科FC交换机)恢复为出厂设置
  20. node14 升级 node16 后 vue2 项目中 sass 报错问题

热门文章

  1. 我喜欢的郭敬明的文字
  2. MySQL slave相关参数
  3. 大数据告诉你何时何地买手机最划算!
  4. [内推] 微软亚洲研究院(上海)热招研究员和开发工程师:人工智能、云和边缘计算、大数据与知识挖掘等...
  5. Platt scaling
  6. KCF核相关滤波跟踪
  7. Tesseract-OCR引擎的安装
  8. execjs._exceptions.ProcessExitedWithNonZeroStatus
  9. R语言交叉验证(详细)
  10. Win10C盘满了怎么清理?如何清理电脑C盘?