Authored by ccbikai

微信获取 Token 功能实现

  1 +'use strict';
  2 +
  3 +/*
  4 + * 生成微信分享所需的签名
  5 + * bikai <kai.bi@yoho.cn>
  6 + * 2016.6.15
  7 + */
1 const request = require('request-promise'); 8 const request = require('request-promise');
2 const Promise = require('bluebird'); 9 const Promise = require('bluebird');
  10 +const crypto = require('crypto');
3 const logger = require('../../../library/logger'); 11 const logger = require('../../../library/logger');
  12 +const cache = require('../../../library/cache');
  13 +
  14 +const appId = 'wx75e5a7c0c88e45c2';
  15 +const secret = 'ce21ae4a3f93852279175a167e54509b';
  16 +
  17 +const sha1 = (etr) => {
  18 + const generator = crypto.createHash('sha1');
  19 +
  20 + generator.update(etr);
  21 + return generator.digest('hex');
  22 +};
  23 +
  24 +const accessTokenCacheKey = 'wechatShare:accessToken';
  25 +const ticketCacheKey = 'wechatShare:ticket';
4 26
5 -const appId = '';  
6 -const secret = ''; 27 +// 微信 JS 接口签名校验工具 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
7 28
8 const wechat = { 29 const wechat = {
9 getAccessToken: Promise.coroutine(function* () { 30 getAccessToken: Promise.coroutine(function* () {
  31 + let accessToken = yield cache.get(accessTokenCacheKey);
  32 +
  33 + if (accessToken) {
  34 + return accessToken;
  35 + }
  36 +
  37 + logger.info('调用微信 API 获取 accessToken');
10 return request({ 38 return request({
11 url: 'https://api.weixin.qq.com/cgi-bin/token', 39 url: 'https://api.weixin.qq.com/cgi-bin/token',
12 qs: { 40 qs: {
13 grant_type: 'client_credential', 41 grant_type: 'client_credential',
14 appid: appId, 42 appid: appId,
15 secret: secret 43 secret: secret
16 - } 44 + },
  45 + json: true
  46 + }).then((res) => {
  47 +
  48 + // accessToken 有效期 7200s,缓存 7100s
  49 + cache.set(accessTokenCacheKey, res.access_token, 7100).catch((err) => {
  50 + logger.error('微信分享 Token, 缓存 accessToken 时出错', JSON.stringify(err));
  51 + });
  52 + return res.access_token;
17 }).catch((err) => { 53 }).catch((err) => {
18 logger.error('微信分享 Token, 获取 accessToken 时出错', JSON.stringify(err)); 54 logger.error('微信分享 Token, 获取 accessToken 时出错', JSON.stringify(err));
19 }); 55 });
20 }), 56 }),
21 57
22 getTicket: Promise.coroutine(function* (accessToken) { 58 getTicket: Promise.coroutine(function* (accessToken) {
  59 + let ticket = yield cache.get(ticketCacheKey);
  60 +
  61 + if (ticket) {
  62 + return ticket;
  63 + }
  64 +
  65 + logger.info('调用微信 API 获取 ticket');
23 return request({ 66 return request({
24 url: 'https://api.weixin.qq.com/cgi-bin/ticket/getticket', 67 url: 'https://api.weixin.qq.com/cgi-bin/ticket/getticket',
25 qs: { 68 qs: {
26 access_token: accessToken, 69 access_token: accessToken,
27 type: 'jsapi' 70 type: 'jsapi'
28 - } 71 + },
  72 + json: true
  73 + }).then(res => {
  74 +
  75 + // ticket 有效期 7200s,缓存 7100s
  76 + cache.set(ticketCacheKey, res.ticket, 7100).catch((err) => {
  77 + logger.error('微信分享 Token, 缓存 ticket 时出错', JSON.stringify(err));
  78 + });
  79 + return res.ticket;
29 }).catch((err) => { 80 }).catch((err) => {
30 logger.error('微信分享 Token, 获取 ticket 时出错', JSON.stringify(err)); 81 logger.error('微信分享 Token, 获取 ticket 时出错', JSON.stringify(err));
31 }); 82 });
32 }), 83 }),
33 84
34 - calcSignature: Promise.coroutine(function* () {  
35 - return yield Promise.resolve(true); 85 + calcSignature: Promise.coroutine(function* (data) {
  86 + let accessToken = yield this.getAccessToken();
  87 +
  88 + data = Object.assign({
  89 + noncestr: Math.random().toString(36).substr(2, 15),
  90 + timestamp: Math.floor(Date.now() / 1000) + '',
  91 + ticket: yield this.getTicket(accessToken)
  92 + }, data);
  93 + const str = `jsapi_ticket=${data.ticket}&noncestr=${data.noncestr}&timestamp=${data.timestamp}&url=${data.url}`;
  94 +
  95 + return sha1(str);
36 }) 96 })
37 }; 97 };
38 98
  99 +// 测试
  100 +// wechat.calcSignature({
  101 +// url: 'http://www.yohobuy.com/boys'
  102 +// }).then(console.log);
  103 +
39 module.exports = wechat; 104 module.exports = wechat;