微信JS SDK配置授权,实现分享接口

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信JS SDK配置授权,实现分享接口相关的知识,希望对你有一定的参考价值。

微信开放的JS-SDK面向网页开发者提供了基于微信内的网页开发工具包,最直接的好处就是我们可以使用微信分享、扫一扫、卡券、支付等微信特有的能力。7月份的时候,因为这个分享的证书获取问题深深的栽了一坑,后面看到“config:ok”的时候真的算是石头落地,瞬间感觉世界很美好..

这篇文章是微信开发的很多前置条件,包括了服务端基于JAVA的获取和缓存全局的access_token,获取和缓存全局的jsapi_ticket,以及前端配置授权组件封装,调用分享组件封装。

配置授权思路:首先根据access_token获取jsapi_ticket,在通过获取到的jsapi_ticket以及随机生成的字符串、时间戳,再加上需要授权的页面地址url,进行SHA-1加密,返回加密字符串,最后根据加密串调用微信提供的config接口。

配置JS接口安全域名

公众平台--公众号设置--功能设置--js接口安全域名

技术分享

 

获取、缓存全局的access_token

技术分享
  /**
     * 微信全局票据 ---->>>> access_token
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public String getBaseAccessToken() throws ClientProtocolException, IOException{
        
        try {
            String value = redisService.get("WEIXIN_BASE_ACCESS_TOKEN");
            if (!StringUtils.isEmpty(value)) {
                LOGGER.info("Get base access_token from redis is successful.value:{}",value);
                return value;
            }else{
                synchronized (this) {
                    //缓存中没有、或已经失效
                    String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+WX_APPID+"&secret="+ WX_APPSECRET;
                    String rs = apiService.doGet(url);
                    
                    JSONObject obj_content = JSONObject.parseObject(rs);
                    String accessToken = obj_content.getString("access_token");
                    Integer time = Integer.parseInt(obj_content.getString("expires_in").toString());
                    
                    //写缓存
                    redisService.set("WEIXIN_BASE_ACCESS_TOKEN", accessToken, time - 3600);
                    LOGGER.info("Set base access_token to redis is successful.parameters time:{},realtime",time,time-3600);
                    return accessToken;
                }
            }
        } catch (Exception e) {
            LOGGER.error("Get base access_token from redis is error.");
        }
        return null;
    }
技术分享

先从缓存中取key为“WX_BASE_ACCESS_TOKEN” ,如果命中直接返回值,反之通过httpclient发送GET请求调用微信提供的接口获取全局的access_token,同时将取到的值写入缓存。

 

获取、缓存全局的jsapi_ticket

技术分享
  /**
     * jsapi_ticket是公众号用于调用微信JS接口的临时票据
     * @return
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public String getJsapiTicket() throws ClientProtocolException, IOException{
        try {
            String value = redisService.get("WEIXIN_JS_API_TICKET");
            if (!StringUtils.isEmpty(value)) {
                return value;
            }else{
                synchronized (this) {
                    //缓存中没有、或已经失效
                    //获取全局的access_token,唯一票据
                    String accessToken = getBaseAccessToken();
                    
                    String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken +"&type=jsapi";
                    
                    String rs = apiService.doGet(url);
                    
                    JSONObject obj_content = JSONObject.parseObject(rs);
                    String jsapi_ticket = obj_content.getString("ticket");
                    Integer time = Integer.parseInt(obj_content.getString("expires_in").toString());
                    
                    //写缓存
                    redisService.set("WEIXIN_JS_API_TICKET", jsapi_ticket, time - 3600);
                    
                    return jsapi_ticket;
                }
            }
        } catch (Exception e) {
            LOGGER.error("Get js_api_ticket from redis is error:{}",e);
        }
        
        return null;
    }
技术分享

由于获取jsapi_ticket微信有100000次限制,所以必须用上缓存。同理获取access_token,我这里为了保险起见缓存失效时间设置为官方提供的时间再减去一个小时。

 

jssdk加密串获取restful

1.Controller

技术分享
  /**
     * 微信分享证书获取
     * @param 
     * @return signature
     * @throws IOException 
     */
    @RequestMapping(value = "/signature", method = RequestMethod.GET)
    public @ResponseBody String createSignature(
                                @RequestParam String url) throws IOException{

        LOGGER.info("RestFul of createSignature parameters url:{}",url);
        
        try {
            String rs = wechatService.createSignature(url);
            LOGGER.info("RestFul of signature is successful.",rs);
            
            return rs;
        } catch (Exception e) {
            LOGGER.error("RestFul of signature is error.",e);
        }
        
        return null;
    }
技术分享

2.Service

技术分享
  /**
     * 根据jsapi_ticket等参数进行SHA1加密
     * @param nonceStr 随机字符串
     * @param timestamp 当前时间戳
     * @param url 当前页面url
     */
    public String createSignature(String url) throws ClientProtocolException, IOException{
        String nonceStr = create_nonce_str();
        String timestamp = create_timestamp();
        
        String signature = "jsapi_ticket="+getJsapiTicket();
               signature += "&noncestr="+nonceStr;
               signature += "&timestamp="+timestamp;
               signature += "&url="+url;
        
       try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(signature.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (Exception e) {
            LOGGER.error("Signature for SHA-1 is error:{}",e);
        }
       
        Map<String, String> map = new HashMap<String, String>();
        map.put("timestamp", timestamp);
        map.put("nonceStr", nonceStr);
        map.put("signature", signature);
        map.put("appid", WX_APPID);
        return JSON.toJSONString(map, true);
    }
技术分享
技术分享
private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }
技术分享
WX_APPID为公众号appid,通过[email protected]注解从配置文件获取,这里不细说。

3.生成随机字符串

private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

4.时间格式化

private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

到此为止后台全部完成,其实没有太多的解释,仔细读一遍代码,可读性应该还行!

 

封装获取授权组件,实现分享方法

技术分享
require.config({
    urlArgs: "v=20161116" ,
    baseUrl : "/static",
    paths: {
        jweixin: ‘component/jweixin/jweixin-1.0.0‘,
        share: ‘component/wechat/share‘//微信分享组件
    }
})
技术分享

首先通过调用后台接口获取加密字符串,调用微信提供的wx.config()方法

技术分享
  //jsSDK授权
    $.signature = function(wx,opts,currentUrl,callback){

        $.ajax({
            data: {url: currentUrl},
            type: "GET",
            url: WX_ROOT + "wechat/signature",
            success: function (json) {
                if (json) {
                    var data = JSON.parse(json);
                    
                    wx.config({
                        debug: false,
                        appId: data.appid,
                        timestamp: data.timestamp,
                        nonceStr: data.nonceStr,
                        signature: data.signature,
                        jsApiList: [
                            ‘onMenuShareTimeline‘,
                            ‘onMenuShareAppMessage‘,
                            ‘onMenuShareQQ‘,
                            ‘onMenuShareWeibo‘,
                            ‘onMenuShareQZone‘
                        ]
                    });
                    
                    wechatShare.options.isSignature = true;
                    
                    callback && callback(opts,wx);
                }
            }
        });
    }
技术分享

建议:开发环境建议开启调式模式,方便打印日志定位问题debug: true   

所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,我这里用一个全局变量isSignature缓存了是否已经配置授权,然后执行回调。如实现分享接口:

技术分享
  //分享
    $.share = function(opts,wx) {
        var options = {
                currentUrl: window.location.href.split(‘#‘)[0],
                imgUrl: null,
                title: ‘达农保险‘,
                desc: null,
                shareUrl: null
            }
        
        $.extend(true, options, opts || {});
        
        //判断是否已经授权
        if(!wechatShare.options.isSignature){
            $.signature(wx,opts,options.currentUrl,$.share)
        }else{
            wx.ready(function(){
                //分享到朋友圈
                wx.onMenuShareTimeline({
                    title: options.title,
                    link: options.shareUrl,
                    imgUrl: options.imgUrl,
                    success: function () {
                        //分享统计,分享来源 1 朋友圈 2分享给朋友  3分享到QQ  4分享到QQ空间
                        
                    }
                });

                //分享给朋友
                wx.onMenuShareAppMessage({
                    title: options.title,
                    desc: options.desc,
                    link: options.shareUrl,
                    imgUrl: options.imgUrl
                });
            });
        }
        
    }
技术分享

我先确认是否已经配置授权,如果没有授权则调用$.signature()回调函数里传入$.share,有点类似递归调用,当再次回到share方法的时候isSignature已经是true了,则执行wx.ready()方法,再调需要调用的接口,微信开放提供了很多接口给我们,分享只是其中一个。只有想不到的,没有实现不了的.... 

注意:currentUrl 必须是动态获取的,通过window.location.href方法,因为页面分享,微信客户端会在你的链接末尾加入其它参数,所以需要再将url用‘#’割一下,取第一个,如果有中文最好是用encodeURIComponent转义一下,保证签名获取成功。如果报invalid signature,大部分原因是传入的url,和加密算法的问题,仔细检查!

调用:

技术分享
var ua = navigator.userAgent.toLowerCase(),
    isWechat = ua.indexOf(‘micromessenger‘) != -1;//判断是否为微信浏览器
var shareData = {
    title: ‘测试分享’,
    desc: ‘这里是描述,分享到朋友圈不会显示’,
    link: APP_ROOT + ‘/base/downloadApp,//分享后打开的链接,必须在配置的安全域名下
    imgUrl: PIC_PATH + (self.data.shareListData[0].imgSmall || ‘/static/img/coupon/getTicPic.png‘),//分享后显示的图片
    success: function(){
                      setTimeout(function(){
              //运营数据统计
             },0)//伪异步方式调用 }
        }
//微信浏览器分享加载
if(isWechat){
 require([‘jweixin‘],function(wx){
    require([‘share‘],function(){
$.share(shareData,wx);
    })
  })
}   
技术分享
















以上是关于微信JS SDK配置授权,实现分享接口的主要内容,如果未能解决你的问题,请参考以下文章

js处理微信分享配置

微信开发-业务域名JS接口安全域名网页授权域名

微信JS-SDK——微信分享给朋友

前端实现微信平台实现分享

微信公众号开发--微信JS-SDK分享到朋友圈和分享给朋友

微信公众号开发--微信JS-SDK分享到朋友圈和分享给朋友