签名加密方式
阅读官方文档: JS-SDK使用权限签名算法
首先获取 access_token -> AppID(开发者ID) + AppSecret(开发者密码) 获取方式:公众号后台地址-基本配置
其次获取 jsapi_ticket —>携带 access_token 请求链接 (见官方文档)
生成加密方式
最终需要返回如下信息:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,直接UUID 随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
加密算法不在赘述,详情查看 官方文档
{message type="info" content="注意 : access_token 与 jsapi_ticket 有效其为 7200秒(2小时) 微信官方强烈要求做全局缓存"/}
附java实现代码:
@Slf4j
public class WeChatUtil {
private static final String APP_ID = "开发者ID";
private static final String APP_SECRET = "开发者密钥";
private static final long EXPIRATION_TIME_MILLIS = 7200 * 1000; // 7200秒转换为毫秒
private static String accessToken;
private static String jsapiTicket;
private static Date accessTokenLastUpdateTime;
private static Date jsapiTicketLastUpdateTime;
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// 使用线程安全的ConcurrentHashMap来存储accessToken和jsapiTicket,避免多线程并发问题
private static final ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();
// 获取微信配置信息
public static WxConfig getWxConfig(String url) {
String accessToken = getAccessToken();
String jsapiTicket = getJsapiTicket(accessToken);
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(jsapiTicket)) {
//进行加密
String nonceStr = UUID.randomUUID().toString();
Long timestamp = System.currentTimeMillis() / 1000;
Map<String, Object> paramMap = new TreeMap<>();
paramMap.put("noncestr", nonceStr);
paramMap.put("jsapi_ticket", jsapiTicket);
paramMap.put("timestamp", timestamp);
paramMap.put("url", url);
// 拼接参数为字符串
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
String string1 = sb.substring(0, sb.length() - 1); // 去掉最后一个&符号
// 使用SHA1加密
String signature = SHA1(string1);
List<String> jsApiList = new ArrayList<>();
jsApiList.add("jsApiList");
return new WxConfig(true, APP_ID, timestamp, nonceStr, signature, jsApiList);
}
return null;
}
// 获取 access_token
private static String getAccessToken() {
log.info("获取acctoken");
// 检查是否过期
if (accessToken == null || accessTokenLastUpdateTime == null || new Date().getTime() - accessTokenLastUpdateTime.getTime() > EXPIRATION_TIME_MILLIS) {
// 过期或者第一次获取,需要更新 accessToken
updateAccessToken();
}
return accessToken;
}
// 更新 access_token
private static void updateAccessToken() {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APP_ID + "&secret=" + APP_SECRET;
String result = HttpClientManager.httpGetMethod(url, null);
JSONObject jsonObject = JSONObject.parseObject(result);
if (!jsonObject.containsKey("errcode")) {
accessToken = jsonObject.getString("access_token");
accessTokenLastUpdateTime = new Date();
log.info(accessToken);
// 使用 scheduler 定时在7200秒后再次更新 accessToken
scheduler.schedule(WeChatUtil::updateAccessToken, EXPIRATION_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
}
// 获取 jsapi_ticket
private static String getJsapiTicket(String accessToken) {
// 检查是否过期
if (jsapiTicket == null || jsapiTicketLastUpdateTime == null || new Date().getTime() - jsapiTicketLastUpdateTime.getTime() > EXPIRATION_TIME_MILLIS) {
// 过期或者第一次获取,需要更新 jsapiTicket
updateJsapiTicket(accessToken);
}
return jsapiTicket;
}
// 更新 jsapi_ticket
private static void updateJsapiTicket(String accessToken) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
String result = HttpClientManager.httpGetMethod(url, null);
JSONObject jsonObject = JSONObject.parseObject(result);
if (jsonObject.getInteger("errcode") == 0) {
jsapiTicket = jsonObject.getString("ticket");
jsapiTicketLastUpdateTime = new Date();
// 使用 scheduler 定时在7200秒后再次更新 jsapiTicket
scheduler.schedule(() -> updateJsapiTicket(accessToken), EXPIRATION_TIME_MILLIS, TimeUnit.MILLISECONDS);
}
}
// SHA1 加密
private static String SHA1(String str) {
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(str.getBytes("UTF-8"));
byte[] digest = crypt.digest();
// 转换为十六进制字符串
Formatter formatter = new Formatter();
for (byte b : digest) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}