前言
官方开发参考文档
微信JS-SDK 是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。使用之前需要向服务器索要签名,本文结合官方开发文档使用java实现计算签名。
一、获取access_token
上代码
/**
* 获取AccessToken
*
* @return
*/
private String getAccessToken() {
String errMsg = "微信获取accessToken失败";
String redisKey = "HLMCheckup:HhyWechat:AccessToken";
String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
String appid = "";
String secret = "";
//去redis里取accessToken
String accessToken = redisCache.getCacheObject(redisKey);
if (StringUtils.isEmpty(accessToken)) {
//redis里的accessToken已过期,重新计算
String param = "grant_type=client_credential&appid=" + appid + "&secret=" + secret;
String resultJsonStr = HttpUtils.sendGet(accessTokenUrl, param);
if (StringUtils.isEmpty(resultJsonStr)) {
log.error(errMsg);
throw new ServiceException(errMsg);
}
JSONObject resultJsonObject = JSONObject.parseObject(resultJsonStr);
Object errcode = resultJsonObject.get("errcode");
if (errcode != null) {
log.error("微信获取accessToken失败,errcode:{},msg:{}", errcode, resultJsonObject.get("errmsg"));
throw new ServiceException(errMsg);
}
accessToken = resultJsonObject.getObject("access_token", String.class);
Long expires = resultJsonObject.getObject("expires_in", Long.class);
redisCache.setCacheObject(redisKey, accessToken);
redisCache.expire(redisKey, expires);
}
return accessToken;
}
二、获取jsapi_ticket
private String getTicket() {
String ticketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
String ticketRedisKey = "HLMCheckup:HhyWechat:JsApi";
String ticket = redisCache.getCacheObject(ticketRedisKey);
if (StringUtils.isNotEmpty(ticket)) {
return ticket;
}
String param = "access_token=" + getAccessToken() + "&type=jsapi";
String resultJsonStr = HttpUtils.sendGet(ticketUrl, param);
if (StringUtils.isEmpty(resultJsonStr)) {
throw new ServiceException("获取jsapi失败");
}
JSONObject resultJsonObject = JSONObject.parseObject(resultJsonStr);
Integer errcode = resultJsonObject.getObject("errcode", Integer.class);
if (errcode == 0) {
ticket = resultJsonObject.getObject("ticket", String.class);
Long expires = resultJsonObject.getObject("expires_in", Long.class);
redisCache.setCacheObject(ticketRedisKey, ticket);
redisCache.expire(ticketRedisKey, expires);
} else {
log.error("获取jsapi失败:{}", resultJsonObject.getObject("errmsg", String.class));
throw new ServiceException("获取jsapi失败");
}
return ticket;
}
三、准备签名算法的四个参数并进行sha1加密
/**
* 获取js-sdk签名
*
* @param url 调用方传递的参数
* @return
*/
public String getJsSdkSign(String url) throws NoSuchAlgorithmException {
Map paramMap = new HashMap();
paramMap.put("url", url);
paramMap.put("noncestr", generateRandomString(););
paramMap.put("jsapi_ticket", getTicket());
paramMap.put("timestamp", System.currentTimeMillis() /1000);
String requestParam = formatUrlMap(paramMap, false, false);
return SHA1Util.sha1(requestParam);
}
/**
* 获取16位随机字符串
* @return
*/
public String generateRandomString() {
String upperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder(16);
Random random = new Random();
for (int i = 0; i < 16; i++) {
sb.append(upperCaseLetters.charAt(random.nextInt(upperCaseLetters.length())));
}
return sb.toString();
}
/**
* @description: 将参数按照字段名排序
*/
public static String formatUrlMap(Map<String, Object> paraMap, boolean urlEncode, boolean keyToLower) {
String buff = "";
Map<String, Object> tmpMap = paraMap;
try {
List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(tmpMap.entrySet());
// 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
@Override
public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
// 构造URL 键值对的格式
StringBuilder buf = new StringBuilder();
for (Map.Entry<String, Object> item : infoIds) {
if (StringUtils.isNotBlank(item.getKey())) {
String key = item.getKey();
Object val = item.getValue();
if (urlEncode) {
val = URLEncoder.encode(val.toString(), "utf-8");
}
if (keyToLower) {
buf.append(key.toLowerCase() + "=" + val);
} else {
buf.append(key + "=" + val);
}
buf.append("&");
}
}
buff = buf.toString();
if (buff.isEmpty() == false) {
buff = buff.substring(0, buff.length() - 1);
}
} catch (Exception e) {
return null;
}
return buff;
}
sha1加密工具类,上代码
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHA1Util {
public static String sha1(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(input.getBytes());
byte[] output = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : output) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}