后臺(tái)生成并返回前端所需參數(shù)
1:jsapi_ticket
jsapi_ticket是公眾號(hào)用于調(diào)用js接口的臨時(shí)票據(jù)。有效期7200秒燕偶,跟公眾號(hào)普通access_token一樣窍育,必須全局緩存起來(lái)赔桌,因?yàn)檫@個(gè)ticket獲取次數(shù)有限污筷,超過(guò)次數(shù)將無(wú)法使用证薇。
1.1獲取access_token
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
1.2獲取jsapi_ticket
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
2:生成簽名
簽名規(guī)則:
1泳姐、參與簽名的字段包括noncestr(隨機(jī)字符串), 有效的jsapi_ticket, timestamp(時(shí)間戳), url(當(dāng)前網(wǎng)頁(yè)的URL效拭,不包含#及其后面部分)。
2胖秒、對(duì)所有待簽名參數(shù)按照字段名的ASCII 碼從小到大排序(字典序缎患,sort()即可)后,使用URL鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串(string)阎肝。
3挤渔、使用sha1加密拼接成的字符串string。
注意:字段名和字段值都要使用原值风题,不要進(jìn)行url轉(zhuǎn)義
參與的字段:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=調(diào)用js接口的安全域名
2.1:校驗(yàn)簽名
3:后端完整代碼
public net.sf.json.JSONObject getConfig(String url){
//url為前端動(dòng)態(tài)入?yún)? net.sf.json.JSONObject object = new net.sf.json.JSONObject();
String access_token = redisStringService.get("AccessToken");
String jsapi_ticket = redisStringService.get("JsapiTicket");
if(StringUtils.isEmpty(access_token)){
//獲取access_token
String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ wxConfigYml.getWxAppId()
+ "&secret="
+ wxConfigYml.getWxSecret();
String result = HttpUtil.sendGet(tokenUrl);
JSONObject accessObj = JSON.parseObject(result);
String accessToken = accessObj.getString("access_token");
redisStringService.put("AccessToken", accessToken, 7180);
}
if (StringUtils.isEmpty(jsapi_ticket)) {
//獲取jsapi
String jsapiStr = HttpUtil.sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi");
net.sf.json.JSONObject jsapi = net.sf.json.JSONObject.fromObject(JSON.parseObject(jsapiStr));
jsapi_ticket = jsapi.getString("ticket");
redisStringService.put("JsapiTicket",jsapi_ticket,7180);
}
//獲取簽名signature
String noncestr = IdGen.uuid();
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
String str = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + noncestr +
"×tamp=" + timestamp +
"&url=" + url;
//sha1加密
String signature = WechatConfig.sha1(str);
object.put("noncestr",noncestr);
object.put("timestamp",timestamp);
object.put("signature",signature);
object.put("jsapi_ticket",jsapi_ticket);
log.info("jsapi_ticket="+jsapi_ticket);
log.info("noncestr="+noncestr);
log.info("timestamp="+timestamp);
log.info("url="+url);
log.info("signature="+signature);
return object;
}
3.1加密方法
public static String sha1(String str) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字節(jié)數(shù)組轉(zhuǎn)換為 十六進(jìn)制 數(shù)
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 "";
}
3.2httpUtil
public class HttpUtil {
private static CloseableHttpClient httpclient = HttpClients.createDefault();
/**
* 發(fā)送HttpGet請(qǐng)求
* @param url
* @return
*/
public static String sendGet(String url) {
HttpGet httpget = new HttpGet(url);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpget);
} catch (IOException e1) {
e1.printStackTrace();
}
String result = null;
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 發(fā)送HttpPost請(qǐng)求判导,參數(shù)為map
* @param url
* @param map
* @return
*/
public static String sendPost(String url, Map<String, String> map) {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : map.entrySet()) {
formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
HttpPost httppost = new HttpPost(url);
httppost.setEntity(entity);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httppost);
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity1 = response.getEntity();
String result = null;
try {
result = EntityUtils.toString(entity1);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 發(fā)送不帶參數(shù)的HttpPost請(qǐng)求
* @param url
* @return
*/
public static String sendPost(String url) {
HttpPost httppost = new HttpPost(url);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httppost);
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity = response.getEntity();
String result = null;
try {
result = EntityUtils.toString(entity);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String post(String url, String jsonString) {
CloseableHttpResponse response = null;
BufferedReader in = null;
String result = "";
try {
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
httpPost.setConfig(requestConfig);
httpPost.setConfig(requestConfig);
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setHeader("Accept", "application/json");
httpPost.setEntity(new StringEntity(jsonString, Charset.forName("UTF-8")));
response = httpclient.execute(httpPost);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
result = sb.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != response) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
4.常見(jiàn)問(wèn)題
1、前端wx.config配置中的nonceStr字段名稱的's'是大寫(xiě)俯邓。但是后臺(tái)生成簽名的noncestr字段 的‘s'是小寫(xiě)骡楼,千萬(wàn)要注意
2、時(shí)間戳(timestamp)值要記住精確到秒稽鞭,不是毫秒鸟整。
3、生成簽名的url(使用jssdk的頁(yè)面地址朦蕴,這個(gè)頁(yè)面地址可以在瀏覽器訪問(wèn))篮条,包含“弟头?”號(hào)后面的所有參數(shù),不包含“#”號(hào)后面的值涉茧。
如果是靜默授權(quán)或者授權(quán)頁(yè)面同意授權(quán)后跳轉(zhuǎn)到的頁(yè)面赴恨,頁(yè)面路徑會(huì)添加兩個(gè)參數(shù):code和state。
即授權(quán)后跳轉(zhuǎn)頁(yè)面為http://redirect.page.com伴栓,則完整路徑為
http://redirect.page.com?code=kdijafdhjaikeiu20kaiela&state=STATE伦连。
那么生成簽名的url必須為授權(quán)后跳轉(zhuǎn)頁(yè)面的完整路徑。前端獲取這個(gè)路徑:location.href.split('#')[0]