微信 JS-SDK 签名验证
doc: http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
demo:http://demo.open.weixin.qq.com/jssdk/
sandbox:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):
用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
注意事项
1.设置JS接口安全域名
2.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
3.签名用的url必须是调用JS接口页面的完整URL。
4.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
JAVA实现
public class WxSign {
@SuppressWarnings({ "unchecked", "unchecked" })
public static void main(String[] args) throws Exception {
/*
String access_token= WeChat.getAccessToken();
String jsapi_ticket = WeChat.getJsApiTicket(access_token);
*/
//System.out.println("access_token : "+access_token+ " jsapi_ticket: " +jsapi_ticket);
String jsapi_ticket="jsapi_ticket";
String url = "http://cmsplus.com.cn";
Map<String, String> ret = sign(jsapi_ticket, url);
for (Map.Entry entry : ret.entrySet()) {
//System.out.println(entry.getKey() + "======== " + entry.getValue());
}
System.out.println("signature: "+ret.get("signature") + ": timestamp " +ret.get("timestamp"));
System.out.println(createLinkString(ret));
}; //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
} public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
// 注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "×tamp=" + timestamp + "&url=" + url;
//System.out.println(string1);
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
} 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;
} private static String create_nonce_str() {
return UUID.randomUUID().toString();
} private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
public class WeChat {
private static final String ACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
private static final String PAYFEEDBACK_URL = "https://api.weixin.qq.com/payfeedback/update";
/**
* 获取access_token
*
* @return
* @throws Exception
*/
public static String getAccessToken() throws Exception {
String appid = ConfKit.get("AppId");
String secret = ConfKit.get("AppSecret");
String jsonStr = HttpKit.get(ACCESSTOKEN_URL.concat("&appid=") + appid + "&secret=" + secret);
Map<String, Object> map = JSONObject.parseObject(jsonStr);
return map.get("access_token").toString();
} /**
* 获取jsapi_ticket
*
* @return
* @throws Exception
*/
public static String getJsApiTicket(String accessToken) throws Exception {
String jsonStr = HttpKit.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi");
Map<String, Object> map = JSONObject.parseObject(jsonStr);
return map.get("ticket").toString();
} /**
* 获取access_token
*
* @return
* @throws Exception
*/
public static String getAccessToken(String appid, String secret) throws Exception {
String jsonStr = HttpKit.get(ACCESSTOKEN_URL.concat("&appid=") + appid + "&secret=" + secret);
Map<String, Object> map = JSONObject.parseObject(jsonStr);
return map.get("access_token").toString();
} /**
* 支付反馈
*
* @param openid
* @param feedbackid
* @return
* @throws Exception
*/
public static boolean payfeedback(String openid, String feedbackid) throws Exception {
Map<String, String> map = new HashMap<String, String>();
String accessToken = getAccessToken();
map.put("access_token", accessToken);
map.put("openid", openid);
map.put("feedbackid", feedbackid);
String jsonStr = HttpKit.get(PAYFEEDBACK_URL, map);
Map<String, Object> jsonMap = JSONObject.parseObject(jsonStr);
return "0".equals(jsonMap.get("errcode").toString());
} /**
* 判断是否来自微信, 5.0 之后的支持微信支付
*
* @param request
* @return
*/
public static boolean isWeiXin(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (StringUtils.isNotBlank(userAgent)) {
Pattern p = Pattern.compile("MicroMessenger/(\\d+).+");
Matcher m = p.matcher(userAgent);
String version = null;
if (m.find()) {
version = m.group(1);
}
return (null != version && NumberUtils.toInt(version) >= 5);
}
return false;
}
javascript
wx.config({
debug: false,
appId: '${appId}',
timestamp: '${timestamp}',
nonceStr: '${nonceStr}',
signature: '${signature}',
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'hideMenuItems',
'showMenuItems',
'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem',
'translateVoice',
'startRecord',
'stopRecord',
'onRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'uploadVoice',
'downloadVoice',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'getNetworkType',
'openLocation',
'getLocation',
'hideOptionMenu',
'showOptionMenu',
'closeWindow',
'scanQRCode',
'chooseWXPay',
'openProductSpecificView',
'addCard',
'chooseCard',
'openCard'
]
});
wx.ready(function () {
var shareData = {
title: '这是活动的介绍页',
desc: '这里是发送给好友的时候的简介',
link: 'http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
};
//wx.onMenuShareAppMessage(shareData);
wx.onMenuShareAppMessage({
title: '互联网之子',
desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
link: 'http://movie.douban.com/subject/25785114/',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
trigger: function (res) {
// 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
alert('用户点击发送给朋友');
},
success: function (res) {
alert('已分享');
},
cancel: function (res) {
alert('已取消');
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
wx.onMenuShareTimeline(shareData);
// 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
wx.hideMenuItems({
menuList: [
'menuItem:copyUrl'
]
});
//hide
//wx.hideAllNonBaseMenuItem();
//wx.hideOptionMenu();
});
wx.error(function (res) {
alert("error: "+ res.errMsg);
});
实现隐藏复制链接,分享的时候改变分析的地址与内容等,其他接口按照文档来吧,没什么复杂滴。
其他语言实现
Nodejs实现:http://www.57kan.com/show/index/id/15907
https://github.com/willian12345/wechat-JS-SDK-demo
PHP实现:https://github.com/wjfz/weixin-jssdk
Refer:
微信js sdk invalid signature签名错误 问题解决
微信 JS-SDK 签名验证的更多相关文章
- 实战微信JS SDK开发:贺卡制作与播放(1)
前段时间忙于CanTK 2.0的开发,所以博客一直没有更新.CanTK 2.0主要增强了游戏和富媒体的开发,现在编码和测试基本完成了,等文档完成了再正式发布,里面有不少激动人心的功能,等发布时再一一细 ...
- 微信JS SDK接入的几点注意事项
微信JS SDK接入,主要可以先参考官网说明文档,总结起来有几个步骤: 1.绑定域名:先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”.备注:登录后可在“开发者中心”查看对 ...
- 微信js sdk上传多张图片
微信js sdk上传多张图片,微信上传多张图片 该案例已tp3.2商城为例 直接上代码: php代码: public function ind(){ $appid="111111111111 ...
- 调用微信js sdk
场景:需要调用微信获取当前位置的借口. 途径:查看微信 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 .后 ...
- 微信JS SDK配置授权,实现分享接口
微信开放的JS-SDK面向网页开发者提供了基于微信内的网页开发工具包,最直接的好处就是我们可以使用微信分享.扫一扫.卡券.支付等微信特有的能力.7月份的时候,因为这个分享的证书获取问题深深的栽了一坑, ...
- 微信js SDK接口
微信JS-SDK说明文档 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 一.微信登录功能 在进行微信OAut ...
- 微信JS SDK使用权限签名算法
jsapi_ticket 生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据.正常情况下,jsapi_ticket的有效期为7200秒, ...
- 微信js sdk分享开发摘记java版
绑定域名和引入js的就不说了 废话不说直接上代码 public void share(HttpServletRequest request) throws Exception { StringBuff ...
- 微信js sdk动态引用
一般情况下,微信的js-sdk只需要直接引用script即可 <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js&qu ...
- 微信JS SDK Demo 官方案例[转]
摘要: 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用 ...
随机推荐
- Typecho 插件开发基础
<?php /** * 标题 插件说明 * * @package 添加标题 * @author Fan * @version 1.0.0 * @link http://cnblogs.com/f ...
- Ubuntu下配置PHP和CakePHP记录
目前在完成一个PayPal的支付页面,需要有PHP的开发环境,同时,在开发时使用了CakePHP的框架,于是就有了下面的情景. 操作环境: OS:ubuntu-14.04.2-desktop-amd6 ...
- 使用 WLST 和节点管理器来管理服务器
使用节点管理器启动计算机上的服务器 WLST 可以连接至在任何计算机上运行的节点管理器,并能够在此计算机上启动一个或多个 WebLogic Server 实例.要通过此技术使用 WLST 和节点管理器 ...
- GIS数据下载
WorldTile.hdf wuhan.hdf ... openstreetmap GIS空间数据库 分割存储. 检索效率有没有提高? 云地理服务:旅游,遥感数据处理,气温,地质,房价,人口,生活(商 ...
- 终端简单使用 &vim编写代码
vim简单实用 & 用vim编写代码 ## 简单介绍 ## vi 1.c 建立1.c(文件存在,则打开1.c) vi共有三种模式: 按esc进入指令模式 按i进入编辑模式(按i光标位置不变 ...
- Hdu2841 Visible Trees 2017-06-27 22:13 24人阅读 评论(0) 收藏
Visible Trees Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
- POJ2061 Subsequence 2017-05-25 19:49 83人阅读 评论(0) 收藏
Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14709 Accepted: 6210 Desc ...
- shell工具-sort
sort sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出 基本语法 sort [选项] [参数] 选项说明 选项 说明 -n 依照数值大小排序 -r 以相反的顺序排序 - ...
- 七种bond模式说明
第一种模式:mod=0 ,即:(balance-rr) Round-robin policy(平衡抡循环策略) 特点:传输数据包顺序是依次传输(即:第1个包走eth0,下一个包就走eth1….一直循环 ...
- Excel 两列单元格合并超级链接的VBA 写法
Excel 单元格 分两列 (B列存放姓名, C列存放链接) 列如: 姓名 学号 博客地址 1309032022 李汉超 http://www.cnblogs.com/Vpygamalion/ 141 ...