zoukankan      html  css  js  c++  java
  • 微信开发之签名校验及获取openId

    我们要用微信jsapi,以及获取用户openid,就要进行签名校验。

    先捋一下应用jssdk的整个流程:

    步骤一:绑定域名

    先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

    备注:登录后可在“开发者中心”查看对应的接口权限。

    步骤二:引入JS文件

    在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

    备注:支持使用 AMD/CMD 标准模块加载方法加载

    步骤三:通过config接口注入权限验证配置

    所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

    wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
    });

    签名算法见文末的附录1,所有JS接口列表见文末的附录2

    步骤四:通过ready接口处理成功验证

    wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
    });

    步骤五:通过error接口处理失败验证

    wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
    });

    步骤一,二,四,五这里不在说明,主要讲的是第三步,通过config接口注入权限验证配置。

    首先,准备好认证过的微信服务号(认证请看我的另一篇博客“微信公众号认证及支付开通流程”),假设公众号appid为wx0123456789abcdef,公众号开发者密码AppSecret为12345678(32位)。

    引用wechat.js文件,该文件为微信jssdk相关配置,getsign()方法是调用服务器get接口,jsApiList中是需要使用的js接口 列表

    function getsign(){
        $.get('/signature?url='+window.location.href.split('#')[0],function(data){
           var json=JSON.parse(data);
           Timestamp=json.Timestamp;
           Signature=json.Signature;
           wx.config({
               beta:true,
               debug: true,
               appId: AppId, //'<%= AppId %>',
               timestamp: Timestamp, //'<%= Timestamp %>',
               nonceStr: Noncestr, //'<%= Noncestr %>',
               signature: Signature, //'<%= Signature %>',
               jsApiList: [
                   'checkJsApi'
               ]
           });
           wx.ready(function() {
           });
          wx.error(function (res) {
             alert("调用微信jsapi返回的状态:"+res.errMsg);
          });
        });
    }

    下面是服务器端代码实现,这里我用的是node来实现的(还未入门),这里随机字符串应该是随机的,我懒省事就直接写了一个,SHA1加密代码是网上copy的

    var http = require("http")  
    var https=require("https")
    var fs = require("fs")
    var process=require("process");
    var urllib = require('url');  
    var jsapi_ticket='';
    var access_token='';
    https.createServer(function(req,res){
        var response=res;
        var path = urllib.parse(req.url);
        //2小时获取一次jsticket
        setInterval(function(){
            jsapi_ticket='';
            access_token='';
            if(path.pathname=='/signature'){
                //获取token
                gettoken(path,response);
            }else if(path.pathname == "/"){
                sendFile(res,"/join_cyiot.html")
            }else{
                sendFile(res,path.pathname)
            }
        },72000000)
        if(path.pathname=='/signature'){
            gettoken(path,response);
        }else if(path.pathname == "/"){
            sendFile(res,"/join_cyiot.html")
        }else if(path.pathname == "/getOpenId"){
            //根据code获取openid
            var code=path.query.substr(path.query.indexOf('code=')+5);
            var ip = req.headers['x-forwarded-for']||req.ip||req.connection.remoteAddress||req.socket.remoteAddress||eq.connection.socket.remoteAddress||'';
            if(ip.split(',').length>0){
                ip = ip.split(',')[0]
            }
            ip=ip.substr(ip.indexOf('f:')+2);
            https.get('https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx0123456789abcdef&secret=12345678&code='+code+'&grant_type=authorization_code',function(req,res){
                var openid='';
                req.on('data',function(data){
                    openid+=data;
                });
                req.on('end',function(){
                    var openidobj=JSON.parse(openid);
                    openidobj.ip=ip;
                    response.end(JSON.stringify(openidobj))
                })
            })
        }else{
            sendFile(res,path.pathname)
        } 
    }).listen(8007);
    function gettoken(path,response){
        https.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx0123456789abcdef&secret=12345678',function(req,res){  
            var jsondata='';  
            req.on('data',function(data){  
                jsondata+=data;  
            });  
            req.on('end',function(){
                var json=JSON.parse(jsondata);
                access_token=json.access_token;
                if(jsapi_ticket==''||access_token==''){
                    //获取jsticket
                    https.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+json.access_token+'&type=jsapi',function(req,res){  
                        jsondata='';  
                        req.on('data',function(data){  
                            jsondata+=data;  
                        });  
                        req.on('end',function(){
                            var jsonTicket= JSON.parse(jsondata); 
                            jsapi_ticket=jsonTicket.ticket;
                            //时间戳,秒
                            var Timestamp=parseInt(new Date().getTime()/1000);
                            var Noncestr="asdffdsadfasf";//随机字符串
                            //算签名并返回
                            var Signature=SHA2("jsapi_ticket="+jsonTicket.ticket+"&noncestr="+Noncestr+"&timestamp="+Timestamp+"&"+path.query);
                            response.end(JSON.stringify({Timestamp:Timestamp,Signature:Signature,jsonTicket:jsonTicket,url:path.query}));                      
                        });
                    }); 
                }else{
                    //时间戳,秒
                    var Timestamp=parseInt(new Date().getTime()/1000);
                    var Noncestr="asdffdsadfasf";//随机字符串
                    //算签名并返回
                    var Signature=SHA2("jsapi_ticket="+jsapi_ticket+"&noncestr="+Noncestr+"&timestamp="+Timestamp+"&"+path.query);
                    response.end(JSON.stringify({Timestamp:Timestamp,Signature:Signature,jsonTicket:jsapi_ticket,url:path.query}));
                }          
            });
    
        });
    }
    function sendFile(res,path){  
        var path = process.cwd()+path;  
        fs.readFile(path,function(err,stdout,stderr){  
            if(!err){  
                var data = stdout;  
                var type = path.substr(path.lastIndexOf(".")+1,path.length)  
                res.writeHead(200,{'Content-type':"text/"+type});
                res.write(data);  
            }  
            res.end();  
        })  
    }  
    // SHA1  
    function add(x, y) {  
        return((x & 0x7FFFFFFF) + (y & 0x7FFFFFFF)) ^ (x & 0x80000000) ^ (y & 0x80000000);  
    }  
      
    function SHA1hex(num) {  
        var sHEXChars = "0123456789abcdef";  
        var str = "";  
        for(var j = 7; j >= 0; j--)  
            str += sHEXChars.charAt((num >> (j * 4)) & 0x0F);  
        return str;  
    }  
      
    function AlignSHA1(sIn) {  
        var nblk = ((sIn.length + 8) >> 6) + 1,  
            blks = new Array(nblk * 16);  
        for(var i = 0; i < nblk * 16; i++) blks[i] = 0;  
        for(i = 0; i < sIn.length; i++)  
            blks[i >> 2] |= sIn.charCodeAt(i) << (24 - (i & 3) * 8);  
        blks[i >> 2] |= 0x80 << (24 - (i & 3) * 8);  
        blks[nblk * 16 - 1] = sIn.length * 8;  
        return blks;  
    }  
      
    function rol(num, cnt) {  
        return(num << cnt) | (num >>> (32 - cnt));  
    }  
      
    function ft(t, b, c, d) {  
        if(t < 20) return(b & c) | ((~b) & d);  
        if(t < 40) return b ^ c ^ d;  
        if(t < 60) return(b & c) | (b & d) | (c & d);  
        return b ^ c ^ d;  
    }  
      
    function kt(t) {  
        return(t < 20) ? 1518500249 : (t < 40) ? 1859775393 :  
            (t < 60) ? -1894007588 : -899497514;  
    }  
      
    function SHA1(sIn) {  
        var x = AlignSHA1(sIn);  
        var w = new Array(80);  
        var a = 1732584193;  
        var b = -271733879;  
        var c = -1732584194;  
        var d = 271733878;  
        var e = -1009589776;  
        for(var i = 0; i < x.length; i += 16) {  
            var olda = a;  
            var oldb = b;  
            var oldc = c;  
            var oldd = d;  
            var olde = e;  
            for(var j = 0; j < 80; j++) {  
                if(j < 16) w[j] = x[i + j];  
                else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);  
                t = add(add(rol(a, 5), ft(j, b, c, d)), add(add(e, w[j]), kt(j)));  
                e = d;  
                d = c;  
                c = rol(b, 30);  
                b = a;  
                a = t;  
            }  
            a = add(a, olda);  
            b = add(b, oldb);  
            c = add(c, oldc);  
            d = add(d, oldd);  
            e = add(e, olde);  
        }  
        SHA1Value = SHA1hex(a) + SHA1hex(b) + SHA1hex(c) + SHA1hex(d) + SHA1hex(e);  
        return SHA1Value.toUpperCase();  
    }  
      
    function SHA2(sIn) {  
        return SHA1(sIn).toLowerCase();  
    } 

    根据请求返回的随机字符串,时间戳,加上签名和appid进行校验即可,整个流程不算复杂,但是自己做下来报了非常多次错误,大小写以及一些细节都要注意,格式与上述代码中一致即可。

    获取openid的js代码

    function getQueryString(name) {
                    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
                    var r = window.location.search.substr(1).match(reg);
                    if (r != null) return unescape(r[2]); return null;
                }
                var code = getQueryString("code");
                var redirecturl=encodeURIComponent('微信后台配置的授权域名') ;
                if(!code){
                    window.location.href='https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx0123456789abcdef&redirect_uri='+redirecturl+'&response_type=code&scope=snsapi_base&state=0#wechat_redirect'
                }else{
                    $.get('/getOpenId?code='+code+'',function(data){    
                        window.localStorage.setItem('openidobj',data);
                    })
                }

    上述方法中微信提供的获取code的接口中,scope参数为应用授权作用域,它的值有两种,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )

    其他也就没啥了,按照微信官方文档,一步步细心点就可以了。

  • 相关阅读:
    centos安装时各个版本的含义
    centos或者ubuntu设置ssh免密码登陆
    centos配置网卡
    如何卸载centos中自带的Java
    基于VHDL的8255可编程并行接口电路设计
    Norns.Urd 中的一些设计
    手把手教你写DI_3_小白徒手支持 `Singleton` 和 `Scoped` 生命周期
    手把手教你写DI_2_小白徒手撸构造函数注入
    手把手教你写DI_1_DI框架有什么?
    手把手教你写DI_0_DI是什么?
  • 原文地址:https://www.cnblogs.com/xianghuali/p/8509411.html
Copyright © 2011-2022 走看看