企业微信号 —— 安全域名配置需要通过验证(如下图)
微信公众 ——— 安全域名配置
设置 ——>公众号设置 ——> 功能设置 ——>JS接口安全域名设置 (如下图)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>扫一扫title>
head>
<body>
<div style="color:red" id="jshref">div>
<script src="http://res2.wx.qq.com/open/js/jweixin-1.4.0.js">script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js">script>
<script>
var wxAppId = "";
var timestamp = "";
var nonce_str = "";
var signature = "";
var url = "../../share.do?share";
var data = { urlSigna: encodeURIComponent(window.location.href)};
jQuery.getJSON(url, data, function (backdata){
wxAppId = backdata.obj.wxAppId;
timestamp = backdata.obj.timesTamp;
nonce_str = backdata.obj.noncestr;
signature = backdata.obj.signature;
wx.config({
debug:false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出, 仅在pc端时才会打印。
appId: wxAppId,// 必填,公众号的唯一标识
timestamp: timestamp,// 必填,生成签名的时间戳
nonceStr: nonce_str,// 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: ['scanQRCode']
});
wx.ready(function () {
wx.scanQRCode({
needResult: 1,
desc: 'scanQRCode desc',
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
alert(res.resultStr);//扫描结果
},
cancel:function(){
history.back();
}
});
});
wx.error(function (res) {
alert("错误信息== " + JSON.stringify(res));
});
});
script>
body>html>
Controller
@RequestMapping(params = "share", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public AjaxJson share(HttpServletRequest request, @RequestParam String urlSigna) throws IOException {
AjaxJson j = new AjaxJson();
WeiXinUtils wx = new WeiXinUtils();
urlSigna = URLDecoder.decode(urlSigna, "UTF-8");
Map<String, Object> wxMap = wx.getSignature(urlSigna);
wxMap.put("wxAppId", WeiXinUtils.APPID);
j.setObj(wxMap);
j.setSuccess(false);
return j;
}
获取签名的Utils
package com.xxx.xxx.xxxxx;
import java.io.IOException;
import java.util.*;
import com.appiot.hp.util.HttpClientUtil;
import net.sf.json.JSONObject;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.log4j.Logger;
/**
* Utils - 微信操作工具类
* add by sl on 2015-12-04 09:42:34
* @author XIAER Team
* @version 1.0
*/
public final class WeiXinUtils {
private static Logger logger = Logger.getLogger(WeiXinUtils.class);
//个人公众号
public static final String APPID = "wxf34602xxxxxxx21";
public static final String APP_SECRET ="90cbc20189cd47xxxxxxxxxxx2b905";
private static final Map map = new HashMap();
/**
* 获取accessToken
* @return accessToken
*/
public static String getAccess_token(String wxAppId, String secret) {
// String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ wxAppId +"&secret=" + secret;
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+ wxAppId +"&corpsecret="+ secret;
JSONObject jsonobject = HttpClientUtil.sendGet(url, null);
return jsonobject.getString("access_token");
}
/**
* 获取jsapi_ticket
* @author WFJ
* @time 2017年4月4日21:50:52
* @return
*/
public static String getJsapiTicket(){
String accessToken = "";
accessToken = getAccess_token(APPID, APP_SECRET);
// String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token="+accessToken+"&type=jsapi";
JSONObject jsonobject = HttpClientUtil.sendGet(url, null);
return jsonobject.getString("ticket");
}
/**
* 获取微信签名signature
* @param url jsapi_ticket
* add by zl on 2016-2-2
* @return signature
* @throws IOException
*/
public Map<String, Object> getSignature(String url) throws IOException {
Map<String, Object> wxMap = new HashMap<String, Object>();
String jsapi_ticket = "";
Long timeJt = (Long) map.get("timeJt");
jsapi_ticket = (String) map.get("jsapi_ticket");
Long nowDateJt = new Date().getTime();
if (jsapi_ticket != null && timeJt != null && ((nowDateJt - timeJt) < 7200 * 1000L)) {
System.out.println("jsapi_ticket 存在");
System.out.println("nowDateJt - timeJt=="+(nowDateJt - timeJt));
} else {
jsapi_ticket = getJsapiTicket();
System.out.println("jsapi_ticket 获取");
map.put("jsapi_ticket",jsapi_ticket);
map.put("timeJt",nowDateJt);
}
//随机字符串和时间戳
String new_novestr = RandomStringUtils.randomAlphanumeric(16); //随机字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳
String signature = "";
// 拼接字符串
String string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + new_novestr + "×tamp=" + timestamp + "&url=" + url;
signature = CheckUtil.SHA1(string1);
System.out.println("签名=="+signature);
wxMap.put("noncestr", new_novestr);
wxMap.put("timesTamp", timestamp);
wxMap.put("signature", signature);
return wxMap;
}
}
CheckUtil
package com.xxx.xxx.xxxx;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.UUID;
public class CheckUtil {
/**
* 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式 (即 key1=value1&key2=value2…)拼接成字符串string1
* @return
*/
public static String SHA1(String decript) {
try {
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
发送请求获取accessToken 和 jsapi_ticket的get方法
package com.xxx.xxx.xxxx;
import com.alibaba.fastjson.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
public class HttpClientUtil {
/**
* 向指定URL发送GET方法的请求
*
* @param url 发送请求的URL
* @param param 请求参数,单个参数
* @return URL 所代表远程资源的响应结果
*/
public static JSONObject sendGet(String url, String param) {
String result = "";
JSONObject retJson = new JSONObject();
BufferedReader in = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
// System.out.println("line====="+line);
}
if (StringUtils.isNotEmpty(result) && isJson(result)) {//数据不为空,进行转换为JSONObject格式数据进行返回
retJson = JSONObject.fromObject(result);
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
retJson.put("status", "102");
retJson.put("msg", "发送GET请求出现异常:" + e);
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return retJson;
}
}
校验地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
当校验获取到的签名和后台获取到的签名一致时,证明你的代码正确,但任然报签名错误 invalid signature,可能是你的安全域名配置有问题,页面动态获取的url地址不是你配置的安全域名