1、问题描述

公众号中的H5有个业务场景,要分享页面给好友,但是因为是在微信中分享,分享的链接微信是不认的,需要首先使用签名认证,认证后才能分享,按照微信官网api,首先需要获取token,然后再根据token获取jsapiticket,然后再将随机数、时间戳、url等按照keyvalue排序加密去认证,java后端实现了下,分享下代码,给需要的朋友。

2、解决方案

2.1 官方文档

官方文档才是yyds,首先查看微信开发者文档(https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html),如下:

附录1-JS-SDK使用权限签名算法
jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html用第一步拿到的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
注意事项签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。签名用的url必须是调用JS接口页面的完整URL。出于安全考虑,开发者必须在服务器端实现签名的逻辑。如出现invalid signature 等错误详见附录5常见错误及解决办法。

官网文档简要来说有几点:

(1)获取jsapi_ticket

首先拿appid与secret换取全局的access_token,然后通过access_token获取jsapi_ticket,这两个值的时效都是是7200秒(2个小时),access_token是全局的,简单说类似管理员权限,每天调用次数有限,2000次/日,这个提到全局的,就有局部的,使用过网页权限的(自定义菜单,H5跳转),也有个access_token,调用次数不限;因为access_token和jsapi_ticket每日调用次数有限,需要把这个值进行缓存;

(2)签名加密

排序、加密,需要对noncestr(随机字符串)、 有效的jsapi_ticket, timestamp(时间戳)、 url,对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1,然后sha1加密;

2.2 代码实现

一步一步来说吧,首先说下关于缓存token和jsapi_ticket的问题,很多方案都是直接放到redis中,但是目前项目比较简单,类似前置机的概念,项目周期也短,就这2个值,还的部署下redis,感觉划不来,就直接库放数据中,弄个定时的标签,整点刷一下,一天刷12次,24个值,稳定可靠,关于存储数据库和刷新就不在这里介绍了。

(1)首先获取access_token

    /***  获取token* @return*/@PostMapping("/getWXaccessToken")public String getWXaccessToken() {String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret=" +secret;String resp = restTemplate.getForObject(url, String.class);JSONObject resJson = JSONObject.parseObject(resp);return resJson.getString("access_token");}

简要说明:

这里就是首先new RestTemplate(),然后拼接下appId和secret,就获取access_token,然后把这个access_token存到数据库中,然后提供查询就好了;

(2)获取jsapi_ticket

    /***  入参为token,返回ticket* @param token* @return*/@PostMapping("/getWXJsapiTicket")public String getWXJsapiTicket(String token) {String ticket = null;if (StringUtils.isBlank(ticket)) {String url ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token +"&type=jsapi";String resp = restTemplate.getForObject(url, String.class);JSONObject resJson = JSONObject.parseObject(resp);return resJson.getString("ticket");}return ticket;}

拼接下access_token,然后把这个access_token存到数据库中,然后提供查询就好了;

(3)随机数

    /***  获取随机数* @param length* @return*/@PostMapping("/getRandomStr")public  String getRandomStr(int length) {String base ="fdajfkdajsklfjafdkjxjkljfadnfdnamn12687";int randomNum;char randomChar;Random random =new Random();StringBuffer str =new StringBuffer();for (int i =0; i < length; i++) {randomNum = random.nextInt(base.length());randomChar = base.charAt(randomNum);str.append(randomChar);}return str.toString();}

(4) 获取签名,完结

  /***   入参为url* @param reqJson* @return*/@PostMapping("/getWXSign")public String getWXSign(@RequestBody JSONObject reqJson) {String url = reqJson.getString("url");long timeStampSec = System.currentTimeMillis() /1000;String timestamp = String.format("%010d", timeStampSec);String nonceStr = getRandomStr(8);String[] urls = url.split("#");String newUrl = urls[0];JSONObject respJson =new JSONObject();String[] signArr =new String[]{"url=" + newUrl,"jsapi_ticket=" + getWXJsapiTicket(getWXaccessToken()),"noncestr=" + nonceStr,"timestamp=" + timestamp};Arrays.sort(signArr);String signStr = StringUtils.join(signArr,"&");String resSign = DigestUtils.sha1Hex(signStr);respJson.put("appId", appId);respJson.put("timestamp", timestamp);respJson.put("nonceStr", nonceStr);respJson.put("signature", resSign);return respJson.toJSONString();}

**简要说明:**简单来说就是获取jsapiticket,然后值排序,做下sha1加密就可以了。


完整类:

测试,使用的使用根据自己业务场景,稍作改动吧

@RestController
@RequestMapping("/api/wx")
@Api(value = "测试")
public class WXShareController {private static final Logger logger = LoggerFactory.getLogger(WXShareController.class);private static final String appId ="ruanjianlaowang";private static final String secret ="dashuaige";RestTemplate restTemplate = new RestTemplate();/***   入参为url* @param reqJson* @return*/@PostMapping("/getWXSign")public String getWXSign(@RequestBody JSONObject reqJson) {String url = reqJson.getString("url");long timeStampSec = System.currentTimeMillis() /1000;String timestamp = String.format("%010d", timeStampSec);String nonceStr = getRandomStr(8);String[] urls = url.split("#");String newUrl = urls[0];JSONObject respJson =new JSONObject();String[] signArr =new String[]{"url=" + newUrl,"jsapi_ticket=" + getWXJsapiTicket(getWXaccessToken()),"noncestr=" + nonceStr,"timestamp=" + timestamp};Arrays.sort(signArr);String signStr = StringUtils.join(signArr,"&");String resSign = DigestUtils.sha1Hex(signStr);respJson.put("appId", appId);respJson.put("timestamp", timestamp);respJson.put("nonceStr", nonceStr);respJson.put("signature", resSign);return respJson.toJSONString();}/***  入参为token,返回ticket* @param token* @return*/@PostMapping("/getWXJsapiTicket")public String getWXJsapiTicket(String token) {String ticket = null;if (StringUtils.isBlank(ticket)) {String url ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token +"&type=jsapi";String resp = restTemplate.getForObject(url, String.class);JSONObject resJson = JSONObject.parseObject(resp);return resJson.getString("ticket");}return ticket;}/***  获取token* @return*/@PostMapping("/getWXaccessToken")public String getWXaccessToken() {String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret=" +secret;String resp = restTemplate.getForObject(url, String.class);JSONObject resJson = JSONObject.parseObject(resp);return resJson.getString("access_token");}/***  获取随机数* @param length* @return*/@PostMapping("/getRandomStr")public  String getRandomStr(int length) {String base ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";int randomNum;char randomChar;Random random =new Random();StringBuffer str =new StringBuffer();for (int i =0; i < length; i++) {randomNum = random.nextInt(base.length());randomChar = base.charAt(randomNum);str.append(randomChar);}return str.toString();}
}

更多信息请关注公众号:「软件老王」,关注不迷路,软件老王和他的IT朋友们,分享一些他们的技术见解和生活故事。

微信分享(JS-SDK权限签名算法)-Java实现相关推荐

  1. 微信分享接口SDK(前端js和后端php)

    微信分享接口SDK 1,帮兄弟对接微信公众号上的分享朋友圈接口对接:签名一定要用微信签名工具去生成比对下代码中签名规则是否一致:好,下面讲下对接顺序: 2,首先:我分享的页面是index.html,所 ...

  2. 微信开放JS SDK,再次给浏览器们上了一课

    2015 年刚刚开始,微信 JS SDK 发布,惊爆众人,HTML5 产业好事连连. JS SDK 这个概念,其实微博和淘宝的开放平台很早前就有,包括手机 QQ 前段时间也推出了几个增强 API,但都 ...

  3. 微信开放JS SDK,这场web巨变意味着什么?

    原文链接:原文链接 作者王安 如有侵权请及时联系,立即删除. 摘要:微信近期推出JS SDK,开放了包括分享.图像.地理位置.微店.微信支付等11个接口.新能力给公众号运营者.开发者更多的玩法.而这样 ...

  4. 微信分享 JS 失效

    转自:方倍工作室 -- 微信分享JS接口失效说明及解决方案 关键字:微信分享 JS 失效  分享到朋友圈  微信分享JS接口目前已失效,以前可以自定义分享的标题.描述.图片.链接地址在微信6.0.2版 ...

  5. 微信分享JS接口失效说明及解决方案

    微信分享JS接口目前已失效,以前可以自定义分享的标题.描述.图片.链接地址在微信6.0.2版本中失效. 官方回复如下: 旧版的获取分享状态及设置分享内容的JS接口一直用于内部业务,并未对外开放,在微信 ...

  6. 微信企业号JS SDK

    微信企业号JS SDK <?php define('CorpID', "wx82e2c31215d9a5a7"); define('CorpSecret', "&q ...

  7. 微信分享js 微信JS-SDK 微信分享接口开发(介绍版)

    https://blog.csdn.net/u013713832/article/details/72778692 本文主要是分享自己的开发过程,希望能给部分存在同样问题的朋友一点点帮助: 最近项目中 ...

  8. 微信分享JS代码 WeixinApi.js

    /**!* 微信内置浏览器的Javascript API,功能包括:** 1.分享到微信朋友圈* 2.分享给微信好友* 3.分享到腾讯微博* 4.新的分享接口,包含朋友圈.好友.微博的分享(for i ...

  9. php转发朋友圈缩略图片,解释最全的,手把手教的微信JS sdk分享设置教程-微信分享插件PHP源码JS-SDK接口,分享到朋友圈 转发好友带缩略图...

    亲们,此文是我上传的有关微信分享插件PHP源码JS-SDK接口的.rar和.zip的说明使用文件 许多朋友都面临自己编写的网站通过微信转发时,无论是分享微信好友或是微信朋友圈时,出现无缩略图显示的问题 ...

最新文章

  1. 【深度学习】基于Colab Pro的TPU训练模型教程(Tensorflow)
  2. Keras中Callback函数的使用
  3. 微信电脑客户端登陆_电脑端的微信只能开一个?简单操作就能随意开
  4. 仓库每天的账怎样做_新年第一站,济南:仓储匠人仓库问题解决与实战力培训...
  5. adf开发_如何在ADF中将参数传递给ActionListener
  6. 283. 移动零golang
  7. 【Flink】This YARN version does not support getSchedulerResourceTypes
  8. 解决gridview导出到excel中汉字出现乱码的问题
  9. javaweb文件压缩下载
  10. 190706每日一句
  11. 怎么转换kux格式?教你把优酷的kux格式转换成avi
  12. 付款方对接银联入网仿真测试系统
  13. vue admin html,vue-admin-template笔记(六)
  14. flex 调用 flash影片剪辑
  15. ps4怎么用html,ps4改dns教程 ps4怎么设置dns
  16. 中国农业大学计算机考研参考书目,中国农业大学(专业学位)计算机技术考研参考书目...
  17. 通过批处理文件bat批量修改图片名称
  18. 在.net gridview 更新回oracle数据库,.net 连接Oracle操作 - cathy_10 - 博客园
  19. 『IT视界』 [职场人生]从软件工程师到IT猎头续:告诉你如何写简历
  20. 把html页面转换为pdf

热门文章

  1. 怎么把视频转成mp3音频?
  2. 有什么推荐书目可以了解社会的残酷?
  3. 题目1(15分)对spark1.txt文件进行筛选,将A或者包含A的字母筛选出来并统计个数,然后输出到dome1文件中。
  4. 华为开发者联盟生态市场·首发上线
  5. 数学物理方法·基础⑦基本初等复变函数的计算公式/方法
  6. 26篇计量经济经典论文复现数据和Stata或R代码
  7. EMUI10的分布式技术:跨越互联、连接万物
  8. 恭喜!勇士获得2022NBA总冠军
  9. delete和delete[]
  10. 大数据、云计算、物联网、数据库、数据仓库、OLAP、OLTP等学习大数据你必须了解的概念,我的学习总结