注意:这是一个系列的文章,只看一篇会有点懵逼的感觉
目录 : http://blog.csdn.net/zzwwjjdj1/article/details/52222653
微信的access_token是从获取开始7200秒后失效,也就是2个小时,需要重新获取.
思路:
access_token必须能在路由中全局访问到,本系列博文在express框架中测试,
所以可以挂载到请求的对象(req)上;
获取一次可以使用2小时,2小时后需要重新获取,这里采用redis数据库存储access_token,
为什么使用redis数据库呢,因为redis数据库也带过期特性,感觉天生就和access_token
的过期匹配,结合起来使用非常方便.开始改造.
var utils = {};
var sha1 = require('sha1');
var request = require('request');
var redis = require("redis");
var client = redis.createClient();
client.on("error", function (err) {
console.log("Error :" , err);
});
client.on('connect', function(){
console.log('Redis连接成功.');
})
//检查微信签名认证中间件
utils.sign = function (config){
return function(req, res, next){
config = config || {};
console.log(config);
var q = req.query;
console.log(q);
var token = config.wechat.token;
var signature = q.signature; //微信加密签名
var nonce = q.nonce; //随机数
var timestamp = q.timestamp; //时间戳
var echostr = q.echostr; //随机字符串
/*
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
*/
var str = [token, timestamp, nonce].sort().join('');
var sha = sha1(str);
if (req.method == 'GET') {
if (sha == signature) {
res.send(echostr+'')
}else{
res.send('err');
}
}
else if(req.method == 'POST'){
if (sha != signature) {
return;
}
next();
}
}
};
/**
* 添加string类型的数据
* @param key 键
* @params value 值
* @params expire (过期时间,单位秒;可为空,为空表示不过期)
*/
utils.set = function(key, value, expire){
return new Promise(function(resolve, reject){
client.set(key, value, function(err, result){
if (err) {
console.log(err);
reject(err);
return;
}
if (!isNaN(expire) && expire > 0) {
client.expire(key, parseInt(expire));
}
resolve(result);
})
})
};
/**
* 查询string类型的数据
* @param key 键
*/
utils.get = function(key){
return new Promise(function(resolve, reject){
client.get(key, function(err,result){
if (err) {
console.log(err);
reject(err);
return;
}
resolve(result);
});
})
};
//Promise化request
utils.request = function(opts){
opts = opts || {};
return new Promise(function(resolve, reject){
request(opts,function(error, response, body){
if (error) {
return reject(error);
}
resolve(body);
})
})
};
module.exports = utils;
/*
*微信相关操作api
*/
var wechatApi = {};
var config = require('../config/config');
var appID = config.wechat.appID;
var appSecret = config.wechat.appSecret;
var utils = require('./utils');
var api = {
accessToken : `${config.wechat.prefix}token?grant_type=client_credential`,
upload : `${config.wechat.prefix}media/upload?`
}
//获取access_token
wechatApi.updateAccessToken = function(){
var url = `${api.accessToken}&appid=${appID}&secret=${appSecret}`;
//console.log(url);
var option = {
url : url,
json : true
};
return utils.request(option).then(function(data){
return Promise.resolve(data);
})
}
module.exports = wechatApi;
//获取,验证access_token,存入redis中
router.use(function(req, res, next) {
//根据token从redis中获取access_token
utils.get(config.wechat.token).then(function(data){
//获取到值--往下传递
if (data) {
return Promise.resolve(data);
}
//没获取到值--从微信服务器端获取,并往下传递
else{
return wechatApi.updateAccessToken();
}
}).then(function(data){
console.log(data);
//没有expire_in值--此data是redis中获取到的
if (!data.expires_in) {
console.log('redis获取到值');
req.accessToken = data;
next();
}
//有expire_in值--此data是微信端获取到的
else{
console.log('redis中无值');
/**
* 保存到redis中,由于微信的access_token是7200秒过期,
* 存到redis中的数据减少20秒,设置为7180秒过期
*/
utils.set(config.wechat.token,`${data.access_token}`,7180).then(function(result){
if (result == 'OK') {
req.accessToken = data.access_token;
next();
}
})
}
})
})