jsapi_ticket是公众号用于调用微信JS接口的临时票据。只用正确的签名才能使用JS调用微信接口,小编在这里整理一个一套完整的获取方法。废话不多说,直接上干货。
//import java.security.MessageDigest;
/*** 获取位置信息签名
* @Author FM_南风
* @Date 2024/3/12 15:52
**/
@Override
public JsonResult getSign(String url) {
logger.info("获取微信授权ticket,用于前端获取客户位置信息:===>【{}】", url);
//url必须是调用JS接口页面的完整URL。
String ticket = TokenUtil.getTicket(redis, APP_ID, APP_SECRET);
logger.info("ticket:===>【{}】", ticket);
//生成11位时间戳
long time11 = System.currentTimeMillis() / 1000;
String timestamp = String.valueOf(time11);
//生成16位随机字符串
String nonce = StringUtil.create16String();
String string1 = "jsapi_ticket=" + ticket + "&noncestr=" + nonce + "×tamp=" + timestamp + "&url=" + url;
// 2.1这里利用了hutool的加密工具类
logger.info("使用sha1加密前的细信息:===>【{}】", string1);
String signature = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = PswUtil.encryptSha1(crypt.digest());
} catch (Exception e) {
logger.info(e.getMessage());
}
logger.info("signature:===>【{}】", signature);
Map<String, String> map = new HashMap<>();
map.put("signature", signature);
map.put("timestamp", timestamp);
map.put("nonce", nonce);
map.put("url", url);
map.put("ticket", ticket);
logger.info("将生成sign信息返回给前端:===>【{}】", map);
return JsonResult.ok(map);
}
其中用到了工具类:TokenUtil.getTicket
public class TokenUtil {
private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);
/***
* 获取微信ticket签名
**/
public static String getTicket(redia, String appId, String appSecret) {
String ticket = redis.getTicket();
if(ticket != null && !ticket.isEmpty()){
return ticket;
}
String token ="token";//你自己的token获取逻辑
String result = HttpUtil.doGet(String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", token));
logger.info("获取ticket返回结果:===>【{}】", result);
JSONObject jsonObject = JSONObject.parseObject(result);
int code = jsonObject.getIntValue("errcode");
ticket = jsonObject.getString("ticket");
if (code == 40014 || code == 40001 || code == 42001) {
logger.info("微信access_token过期或无效,需要重新获取token并生成ticket");
redis.deleteWxToken();
logger.info("删除微信access_token,递归调用生成ticket");
return getTicket(redis, appId, appSecret);
}
redis.saveTicket(ticket);
return ticket;
}
}
HttpUtil.doGet
public class HttpUtil {
/**
* get方式的http请求
* @param httpUrl 请求地址
* @return 返回结果
*/
public static String doGet(String httpUrl) {
HttpURLConnection connection = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
String result = null;// 返回结果字符串
try {
// 创建远程url连接对象
URL url = new URL(httpUrl);
// 通过远程url连接对象打开一个连接,强转成httpURLConnection类
connection = (HttpURLConnection) url.openConnection();
// 设置连接方式:get
connection.setRequestMethod("GET");
// 设置连接主机服务器的超时时间:15000毫秒
connection.setConnectTimeout(15000);
// 设置读取远程返回的数据时间:60000毫秒
connection.setReadTimeout(60000);
// 发送请求
connection.connect();
// 通过connection连接,获取输入流
if (connection.getResponseCode() == 200) {
inputStream = connection.getInputStream();
// 封装输入流,并指定字符集
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
// 存放数据
StringBuilder sbf = new StringBuilder();
String temp;
while ((temp = bufferedReader.readLine()) != null) {
sbf.append(temp);
sbf.append(System.getProperty("line.separator"));
}
result = sbf.toString();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != bufferedReader) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();// 关闭远程连接
}
}
return result;
}
}
StringUtil.create16String();
public class StringUtil {
/***
* 生成16位随机大小写加数字的字符串
**/
public static String create16String(){
String a = "ZXCVBNMASDFGHJKLQWERTYUIOPzxcvbnmasdfghjklqwertyuiop0123456789";
StringBuilder con = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 16; i++) {
con.append(a.charAt(random.nextInt(62)));
}
return con.toString();
}
}
PswUtil.encryptSha1
public class PswUtil {
/***
* 生成微信sha1方法签名
**/
public static String encryptSha1(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
}
这就是一个完整的获取jsapi_ticket生成签名的过程。
注意事项
-
签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
-
签名用的url必须是调用JS接口页面的完整URL。
-
出于安全考虑,开发者必须在服务器端实现签名的逻辑