/**
* 微信公众号签名获取
* @author: qiujun <jun.qiu@yoho.cn>
* @date: 14/11/2017
*/
const config = global.yoho.config;
const crypto = require('crypto');
const request = require('request-promise');
const WechatModel = require('../models/wechat');
const moment = require('moment');
const sha1 = (str) => {
const generator = crypto.createHash('sha1');
generator.update(str);
return generator.digest('hex');
};
// 微信 JS 接口签名校验工具 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
let getAccessToken = function(req, next, appId, secret, prefix) { // 获取access_token
return request({
url: prefix + 'token',
qs: {
grant_type: 'client_credential',
appid: appId,
secret: secret
},
json: true
}).then(res => {
return res;
}).catch(next);
};
let getTicket = function(req, accessToken, next, appId, secret, prefix) { // 获取ticket
return request({
url: prefix + 'ticket/getticket',
qs: {
access_token: accessToken,
type: 'jsapi'
},
json: true
}).then(res => {
return res;
});
};
let calcSigature = function(ticket_res, res) { // 计算signature
let appID = ticket_res.appID;
let ticket = ticket_res.access_ticket;
let nonceStr = Math.random().toString(36).substr(2, 15);
let timestamp = Math.floor(Date.now() / 1000) + '';
let url = ticket_res.url;
let str = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
let signature = sha1(str);
console.log(str + '&signature=' + signature);
let result = {
appId: appID,
nonceStr,
timestamp,
url,
signature
};
// console.log('result', result);
return res.jsonp(result);
};
let getResult = function(wechat_res, req, res, next) { // 向微信接口获取access_token及ticket并计算signature
let appID = wechat_res.appID;
let appSecret = wechat_res.appSecret;
let prefix = wechat_res.prefix;
let mpPrefix = wechat_res.mpPrefix;
let url = wechat_res.url;
let type = wechat_res.type;
return getAccessToken(req, next, appID, appSecret, prefix)
.then(result => { // 先获取accessToken
let access_token = result.access_token;
console.log('token:', access_token);
return getTicket(req, access_token, next, appID, appSecret, mpPrefix)
.then(ticket_res => { // 通过accessToken获取ticket
if (ticket_res && ticket_res.ticket) {
let access_ticket = ticket_res.ticket;
let expired = parseInt(ticket_res.expires_in, 10) - 100;
let create_time = moment().format('YYYY-MM-DD HH:mm:ss');
let expired_time = moment().add(expired, 'seconds').format('YYYY-MM-DD HH:mm:ss');
// console.log('ticket_res:', ticket_res);
req.ctx(WechatModel).
saveAccessKeys(access_token, access_ticket, create_time, expired_time, type)
.then(() => {
let access_res = {
appID: appID,
access_ticket: access_ticket,
url: url
};
calcSigature(access_res, res);
});
} else {
res.jsonp({
appID: appID,
nonceStr: '',
timestamp: '',
url: url,
signature: 'get failed'
});
}
}).catch(next);
});
};
const wechatShare = {
getSignPackage(req, res, next) {
const appID = config.wechat.appID;
const appSecret = config.wechat.appSecret;
const prefix = config.wechat.prefix;
const mpPrefix = config.wechat.mpPrefix;
const url = req.query.pageurl || 'http://www.yoho.cn';
req.ctx(WechatModel).getAccessKeys()
.then(keys_res => { // 先查询数据库中是否有access_token并且未过期
console.log(keys_res);
if (keys_res.length > 0) {
let access_token = keys_res[0].access_token;
let access_ticket = keys_res[0].access_ticket;
let expired = new Date(keys_res[0].access_expired).getTime();
let now = Date.now();
console.log('data_time!', expired, now, keys_res[0].access_expired);
if (now > expired) { // 过期则去 取新的token与ticket 并且更新数据库
return Promise.reject({
type: 'update'
});
} else {
return Promise.resolve({ // 没过期则直接返回数据库中保存的access_ticket
access_token,
access_ticket
});
}
} else {
return Promise.reject({ // 数据库中没有token数据则新增
type: 'save'
});
}
})
.then(access_res => {
access_res = Object.assign({
appID,
url
}, access_res);
calcSigature(access_res, res); // 组合参数, 计算signature
},
fail_res => {
fail_res = Object.assign({
appID: appID,
appSecret: appSecret,
prefix: prefix,
mpPrefix: mpPrefix,
url: url
}, fail_res);
getResult(fail_res, req, res, next); // 向微信接口获取access_token及ticket并计算signature
});
}
};
module.exports = wechatShare;
... ...
/**
* 微信model
* @author: qiujun <jun.qiu@yoho.cn>
* @date: 15/11/2017
*/
const mysqlCli = global.yoho.utils.mysqlCli;
const TABLE_WECHAT = 'wechat_token';
class WechatModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
getAccessKeys() {
let strSql = `select * from ${TABLE_WECHAT} limit 0, 1;`;
return mysqlCli.query(strSql);
}
saveAccessKeys(access_token, access_ticket, access_create_time, access_expired, type) {
let strSql = '';
let params = {
access_token,
access_ticket,
access_create_time,
access_expired
};
if (type === 'save') {
strSql = `insert into ${TABLE_WECHAT}
(access_token, access_ticket, access_create_time, access_expired) values
(:access_token, :access_ticket, :access_create_time, :access_expired);`;
console.log(strSql, params);
return mysqlCli.insert(strSql, params);
} else if (type === 'update') {
strSql = `update ${TABLE_WECHAT} set
access_token = :access_token,
access_ticket = :access_ticket,
access_create_time = :access_create_time,
access_expired = :access_expired`;
console.log(strSql);
return mysqlCli.update(strSql, params);
}
}
}
module.exports = WechatModel;
... ...
... ... @@ -6,7 +6,9 @@
const express = require('express');
const router = express.Router(); // eslint-disable-line
const qiniu = require('./controllers/qiniu');
const wechat = require('./controllers/wechat');
router.get('/gettoken', qiniu.getToken);
router.get('/share/getSignPackage', wechat.getSignPackage);
module.exports = router;
... ...
... ... @@ -74,7 +74,14 @@ module.exports = {
SECRET_KEY: '_x2VtO7fEmylgjojmLi7qwTBtRm30S8BrO0FxOPK',
BUCKET_NAME: 'cmsimg01'
},
yohoSecret: '3bd815162342d9733f06ab6811082c64'
yohoSecret: '3bd815162342d9733f06ab6811082c64',
wechat: {
appID: 'wx1fe49f08f41b6c26',
appSecret: '5670f62abcebcd8d321615b46bd19ef4',
token: 'weixin',
prefix: 'https://api.weixin.qq.com/cgi-bin/',
mpPrefix: 'https://api.weixin.qq.com/cgi-bin/'
}
};
if (isProduction) {
... ... @@ -97,7 +104,7 @@ if (isProduction) {
'https://feature.yoho.cn',
'http://huodong.yoho.cn',
'https://huodong.yoho.cn',
'http://ad.yhurl.com/'
'http://ad.yhurl.com'
],
memcache: {
master: ['memcache1.yohoops.org:12111', 'memcache2.yohoops.org:12111', 'memcache3.yohoops.org:12111'],
... ...
/*
记录微信access_token与ticket
@author: qiuj <jun.qiu@yoho.cn>
@date: 2017-11-15 10:10:17
*/
#注意:GO;分割执行块
use yoho_activity_platform;
GO;
CREATE TABLE IF NOT EXISTS `wechat_token` (
`id` int(8) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`access_token` varchar(200) NOT NULL DEFAULT '',
`access_ticket` varchar(200) NOT NULL DEFAULT '',
`access_create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`access_expired` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARSET=utf8;
GO;
... ...
module.exports = ['_migration', '20170913102356', '20170927092926', '20171025145423', '20171102104558'];
module.exports = ['_migration', '20170913102356', '20170927092926', '20171025145423',
'20171102104558', '20171115144710'];
... ...