关于微信签名signature获取

微信分享的签名算法微信也写有,主要是调用接口需要使用服务器(微信官方文档是这么说的,试了下前端居然特么也可以),不过微信的access_token和jsapi_ticket是有使用次数限制的,所以还是用服务器来获取,得到以后存下来,下次使用判断超时以后再重新获取,这样就够用了,要不然就会出现接口调用次数超出限制这种尴尬的事情了。

如果需要使用自定义分享文案的时候,服务号或者订阅号一定要是已认证的(我的是个人类型的订阅号,不能认证,所以不能使用分享功能)

我这边用的是node做的后台,所以代码用的是js代码,当然其他的也可以,逻辑都一样,代码写法不一样而已。

1.首先是公众号的设置

  我这边申请的是一个订阅号

  首先,要在 开发 -> 基本配置 下,获取到自己的开发者id(appid)和开发者密码(AppSecret),这两个是必须的

  然后要在同目录下的 ip白名单 选项里设置好服务器的ip

  这样,基本服务器设置就算完成了。

2.然后就是我们最擅长的事了——写代码

  

  根据微信官方文档,第一步,我们需要拿到access_token,并且这个access_token有7200秒的有效期,所以拿到access_token以后要存在本地(文件存储或者数据库存储都可以,反正存好就行)

  具体实现代码如下

  首先需要引入node对应的模块(mongodb数据库每次使用还要启动,我嫌麻烦,所以我这边用的是文件存储)

    

1 var express=require('express');
2 var https=require('https');5 var fs = require("fs");
6 var crypto = require('crypto');

  从上往下依次是

    express模块 用来创建一个服务器,分别和前端、微信进行接口对接(在这里貌似没多大用,可以使用http模块代替)

    https模块 用来发送https请求的一个模块(微信请求需要使用https请求,http不行)

    fs模块 文件操作模块,如果是用的数据库就需要换成对应的模块

    crypto模块 加密模块,微信签名算法需要使用sha1算法加密,下边有说到

  模块全部引入,接下来定义一些方便使用的方法

  首先,要开启一个服务器:

 1 app.get("/getconfig",function (req,res) {
 2     res.header("Access-Control-Allow-Origin", "*");
 3     res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
 4     res.header("Access-Control-Allow-Headers", "X-Requested-With");
 5     res.header('Access-Control-Allow-Headers', 'Content-Type');
 6     res.send({
 7                 code:"200",
 8                 data:{},
 9                 result:true
10             });
11             res.end("");
12 });
13 app.listen(8000);

  然后定义阅读和写入文件的方法

 1 //写入文件
 2 function whiteFile(obj,callback){
 3     fs.writeFile(obj.fileName,obj.data,{flag:"w"},function (err) {
 4         if(err){
 5             console.error(obj.name+"文件写入错误");
 6             console.log(err);
 7             return;
 8         }
 9         console.log('文件写入成功');
10         callback(obj.data);
11     });
12 }
13 //读取文件信息
14 function readFile(obj,callback,errback){
15     fs.readFile(obj.fileName,"utf-8",function (err,data) {
16         if(err){
17             console.error(obj.name+"读取错误");
18             return errback(callback);
19         }
20         //console.log(data);
21         if(!data){
22             errback(callback);
23         }else{
24             console.log(data);
25             callback(data);
26         }
27     });
28 }

  然后是使用定义一个发送https请求的方法

 1 //发送一个http get请求
 2 function sendGetRequest(options,callback){
 3     var httpReq=https.request(options, function(httpRes) {
 4         httpRes.on('data',function(chun){
 5             callback(chun);
 6         });
 7         httpRes.on('end',function(){});
 8     });
 9     httpReq.on('error',function(err){
10         console.log("接口调用失败");
11     });
12     httpReq.end();
13 }

  基本需要使用的方法有了,下边就可以请求微信接口了

 1 //获取access_token
 2 function getToken(callback){
 3     readFile({
 4         fileName:"./access_token.txt",
 5         name:"access_token"
 6     },callback,function(cb){
 7         var options={
 8             hostname:"api.weixin.qq.com",
 9             path:"/cgi-bin/token?grant_type=client_credential&appid=您的appid&secret=你的appid对应的密码",
10             method:'GET'
11         };
12         sendGetRequest(options,function(chun){
13             var resObj = JSON.parse(chun.toString());
14             resObj.timestamp = Math.floor((new Date().getTime())/1000);
15             var res = JSON.stringify(resObj);
16             //console.log(res);
17             try {
18                 whiteFile({
19                     fileName:"./access_token.txt",
20                     data:res,
21                     name:"access_token"
22                 },cb);
23             }catch(err){
24                 console.log("文件写入失败");
25                 console.log("access_token:"+res);
26                 cb(res);
27             }
28         });
29     });
30 }
  上边这个方法是获取微信token的方法,我这边首先从本地文件中读取,读取不到再调用接口(我这里只是测试使用,没有做判断,实际操作中需要判断时间戳,如果access_token过期需要删掉文件里的内容重新请求新的access_token)

  access_token有了,下边就是获取jsapi_ticket:

 1 //获取ticket
 2 function getTicket(callback){
 3     readFile({
 4         fileName:"./ticket.txt",
 5         name:"ticket"
 6     },callback,function(cb) {
 7         getToken(function(tokenData){
 8             var token = JSON.parse(tokenData);
 9             //console.log("token:"+JSON.stringify(token));
10             //callback({code:"200",data:{"data":token},result:true});
11             var options = {
12                 hostname: "api.weixin.qq.com",
13                 path: "/cgi-bin/ticket/getticket?access_token=" + token.access_token + "&type=jsapi",
14                 method: 'GET'
15             };
16             sendGetRequest(options, function (chun) {
17                 var resObj = JSON.parse(chun.toString());
18                 resObj.timestamp = Math.floor((new Date().getTime())/1000);
19                 var res = JSON.stringify(resObj);
20                 if (resObj.errcode == 42001) {
21                     getToken(function(){
22                         getTicket(callback);
23                     });
24                 } else if (resObj.ticket) {
25                     try {
26                         whiteFile({
27                             fileName:"./ticket.txt",
28                             data:res,
29                             name:"ticket"
30                         },callback);
31                     }catch(err){
32                         console.log("文件写入失败");
33                         console.log("ticket:"+res);
34                         callback(res);
35                     }
36                 } else {
37                     callback(res);
38                 }
39 
40             });
41         });
42     });
43 }

  jsapi_ticket和token获取和存储逻辑是一样的

  

 

  接下来就是签名的生成

 1 getTicket(function(data){
 2             var dataObj = JSON.parse(data);
 3             var noncestr = "zhangchenguang";
 4             var timestamp = Math.floor((new Date().getTime())/1000);
 5             var url = "http://api-loan.zhmf.com/html/test/testshare.html";
 6             var obj = {
 7                 noncestr,timestamp,url,jsapi_ticket:dataObj.ticket
 8             };
 9             var arr = ["noncestr","jsapi_ticket","timestamp","url"].sort();
10             var string1 = "";
11             for(var i = 0; i < arr.length; i++){
12                 string1 += (arr[i]+"="+obj[arr[i]])+"&";
13             }
14             string1 = string1.slice(0,string1.length-1);
15             console.log(string1);
16             var shasum = crypto.createHash('sha1');
17             shasum.update(string1);
18             var signature = shasum.digest("hex");
19             console.log(signature);
20         });

  生成签名以后,把签名和随机串和appid和时间戳同时通过res.send传给前端:

 1 app.get("/getconfig",function (req,res) {
 2     res.header("Access-Control-Allow-Origin", "*");
 3     res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
 4     res.header("Access-Control-Allow-Headers", "X-Requested-With");
 5     res.header('Access-Control-Allow-Headers', 'Content-Type');
 6         getTicket(function(data){
 7             var dataObj = JSON.parse(data);
 8             var noncestr = "zhangchenguang";
 9             var timestamp = Math.floor((new Date().getTime())/1000);
10             var url = "http://api-loan.zhmf.com/html/test/testshare.html";
11             var obj = {
12                 noncestr,timestamp,url,jsapi_ticket:dataObj.ticket
13             };
14             var arr = ["noncestr","jsapi_ticket","timestamp","url"].sort();
15             var string1 = "";
16             for(var i = 0; i < arr.length; i++){
17                 string1 += (arr[i]+"="+obj[arr[i]])+"&";
18             }
19             string1 = string1.slice(0,string1.length-1);
20             console.log(string1);
21             var shasum = crypto.createHash('sha1');
22             shasum.update(string1);
23             var signature = shasum.digest("hex");
24             console.log(signature);
25             res.send({
26                 code:"200",
27                 data:{
28                     noncestr:noncestr,
29                     timestamp:timestamp,
30                     appId:"wx23599cdec409383c",
31                     signature:signature
32                 },
33                 result:true
34             });
35             res.end("");
36         });
37 });

 

  前端接收到数据后调用wx.config(),并传入对饮的参数就可以获取到对应的微信js权限了(前端实现逻辑上篇随笔写过了)。

posted @ 2017-09-13 16:10  zhangchenguang  阅读(9551)  评论(0编辑  收藏  举报