微信开放平台之JSSDK分享

 微信分享开发流程:

步骤一:绑定域名

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

 

步骤二:引入JS文件

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

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)。

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

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

   见微信官方文档 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

//微信分享
//调用后台接口获取url签名
      shareWXCTerminal: async function(){
        let shareParams = {
          appId: 'xxxxxxxxxxxxxxxxxx',
          url: encodeURIComponent(location.href.split('#')[0])
        }
        const res= await http.post("/weshare/getwxfxSign/ashx", shareParams)
        if(res.data.code==200&&res.data.data!=''){
          var getMsg=res.data.data
          wx.config({
            //注意驼峰命名
            debug: false,  //生产环境需要关闭debug模式
            appId: getMsg.appId, //appId通过微信服务号后台查看
            timestamp: getMsg.timestamp, //生成签名的时间戳
            nonceStr: getMsg.nonceStr, //生成签名的随机字符串
            signature: getMsg.signature, //签名
            jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ','onMenuShareQZone']
          });
          wx.ready(function() {
            wx.onMenuShareTimeline({
              title:'wenjuan', // 分享标题
              link: location.href.split('#')[0]+'#'+location.href.split('#')[1],// 分享链接
              imgUrl: 'http://scrm.taikang.com/d6e18c2231ec926ebae2cc95a55ec3c3(0c95d4edab6d4f5397931f936c731b11).jpg', // 分享图标
              success:function(res){

              }
            }),
            wx.onMenuShareAppMessage({
              title:'标题', // 分享标题
              desc: 'mianshuu', //分享描述
              link: location.href.split('#')[0]+'#'+location.href.split('#')[1],// 分享链接
              imgUrl: 'http://scrm.taikang.com/d6e18c2231ec926ebae2cc95a55ec3c3(0c95d4edab6d4f5397931f936c731b11).jpg', // 分享图标
              success:function(res){

              }
            }),
              wx.onMenuShareQZone({
                title:'标题', // 分享标题
                desc: 'mianshuu', //分享描述
                link: location.href.split('#')[0]+'#'+location.href.split('#')[1],// 分享链接
                imgUrl: 'http://scrm.taikang.com/d6e18c2231ec926ebae2cc95a55ec3c3(0c95d4edab6d4f5397931f936c731b11).jpg', // 分享图标
                success:function(res){

                }
              }),
              wx.onMenuShareQQ({
                title:'标题', // 分享标题
                desc: 'mianshuu', //分享描述
                link: location.href.split('#')[0]+'#'+location.href.split('#')[1],// 分享链接
                imgUrl: 'http://scrm.taikang.com/d6e18c2231ec926ebae2cc95a55ec3c3(0c95d4edab6d4f5397931f936c731b11).jpg', // 分享图标
                success:function(res){

                }
              })
          });
        }

      },

后台步骤

附录1-JS-SDK使用权限签名算法

jsapi_ticket

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html

2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

成功返回如下JSON:

{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

签名算法

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

即signature=sha1(string1)。 示例:

noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value

步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value

步骤2. 对string1进行sha1签名,得到signature:

0f9de62fce790f9a083d5c99e95740ceb90c27ed

注意事项

1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。

2.签名用的url必须是调用JS接口页面的完整URL。

3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。

代码示例:

 @PostMapping("/getwxfxSign/ashx")
    public BaseBean getSignature(@RequestBody Map<String,String> param) throws UnsupportedEncodingException {
        String appId = param.get("appId");
        String url = param.get("url");
        //前端请求中的 url 是 encodeURIComponent(location.href.split('#')[0])处理过的 
        //后端相应的要 解码
        String decodeUrl = URLDecoder.decode(url, "UTF-8");
        SigVO sign = this.sign(appId, decodeUrl);
        return BaseBean.success(sign);
    }

    private SigVO sign(String appid, String url) {
        //32位随机字符串
        String nonceStr = WeShareUtils.CreateNoncestr();
        //时间戳
        String timeStamp = WeShareUtils.GetTimeStamp();
        //签名
        String signature = StringUtils.EMPTY;
        //获取jsapi_ticket
        Map<String, String> resultMap = new HashMap<>();
        getJsapiTicketCatch(appid,resultMap);
        String jsapiTicket = resultMap.get("tick");
        if (StringUtils.isBlank(jsapiTicket)) {
            return null;
        }
        //注意 参数字段全为小写
        String s1 = "jsapi_ticket=" + jsapiTicket + "&noncestr="
                + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(s1.getBytes("UTF-8"));
            signature = WeShareUtils.byteToHex(crypt.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SigVO.builder()
                .appId(appid)
                .timestamp(timeStamp)
                .nonceStr(nonceStr)
                .signature(signature)
                .build();
    }

    private void getJsapiTicketCatch(String appid, Map<String, String> resultMap) {
        long expr = 90 * 60 * 1000L;
        long ex = 5 * 1000L;
        String value = String.valueOf(System.currentTimeMillis() + ex);
        boolean lock = redisLock.lock(appid, value);
        //获取锁
        if (lock) {
            String tick = redisTemplate.opsForValue().get("zqs"+appid);
            if (StringUtils.isNotBlank(tick)) {
                resultMap.put("tick",tick);
            } else {
                //token 通过appid
                BigAuthorizationInfo authorInfoByAppidService = authorizedService.getAuthorInfoByAppidService(appid);
                if (authorInfoByAppidService == null
                        || StringUtils.isBlank(authorInfoByAppidService.getAuthorizer_access_token())) {
                    resultMap.put("tick",null);
                }else {
                    String token = authorInfoByAppidService.getAuthorizer_access_token();
                    String jsapiTicket = WeShareUtils.GetJsapiTicket(token);
                    if (StringUtils.isBlank(jsapiTicket)) {
                        resultMap.put("tick",null);
                    }else {
                        resultMap.put("tick",jsapiTicket);
                        redisTemplate.opsForValue().set("zqs"+appid, jsapiTicket, expr,TimeUnit.MILLISECONDS);
                    }
                }
            }
            //释放锁
            redisLock.unlock(appid, value);
        }

    }

 上述代码未实现定时刷新凭证jsapiTicket  而是通过redis设置失效时间  如果redis中没有需要的凭证

则主动调用获取jsapiTicket 的接口 获取后存入redis中   未避免并发导致 接口调用超出限制次数 所以加锁处理

微信官方的验证签名是否正确的网页工具地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

工具类:

package com.taikang.controller.share.WeShareUtil;

import com.alibaba.fastjson.JSONObject;
import com.taikang.constant.WeChatContants;
import com.taikang.controller.share.TicketJson;
import com.taikang.utils.weChat.WeChatUtils;

import java.util.Formatter;
import java.util.Random;

public class WeShareUtils {
    public static String GetJsapiTicket(String token) {
        String getTickUrl = WeChatContants.GET_TICK_URL;
        String url = String.format(getTickUrl, token);
        String result = WeChatUtils.getUrl(url);
        TicketJson ticketJson = JSONObject.parseObject(result, TicketJson.class);
        int errcode = ticketJson.getErrcode();
        if (errcode==0){
            return ticketJson.getTicket();
        }
        return null;
    }


    public static String GetTimeStamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    public 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;

    }

    public static String CreateNoncestr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder res = new StringBuilder();
        Random rd = new Random();
        for (int i = 0; i < 32; i++) {
            res.append(chars.charAt(rd.nextInt(chars.length() - 1)));
        }
        return res.toString();
    }
}

猜你喜欢

转载自blog.csdn.net/fzzhdp/article/details/85223666
今日推荐