|
|
|
package com.zhonglai.luhui.admin.controller.monitor;
|
|
|
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
import com.ruoyi.common.core.domain.AjaxResult;
|
|
|
|
import com.ruoyi.common.core.page.TableDataInfo;
|
|
|
|
import com.ruoyi.common.utils.DateUtils;
|
|
|
|
import com.ruoyi.common.utils.ServletUtils;
|
|
|
|
import com.ruoyi.common.utils.ip.IpUtils;
|
|
|
|
import com.ruoyi.framework.web.domain.Server;
|
|
...
|
...
|
@@ -9,35 +12,37 @@ import com.ruoyi.system.domain.sys.SysMonitorServer; |
|
|
|
import com.ruoyi.system.domain.sys.SysMonitorServerLog;
|
|
|
|
import com.zhonglai.luhui.action.BaseController;
|
|
|
|
import com.zhonglai.luhui.admin.dto.MonitorServerUploadDto;
|
|
|
|
import com.zhonglai.luhui.admin.qywx.AesException;
|
|
|
|
import com.zhonglai.luhui.admin.qywx.QyWxApplication;
|
|
|
|
import com.zhonglai.luhui.admin.qywx.WXBizMsgCrypt;
|
|
|
|
import com.zhonglai.luhui.admin.service.SendSysMonitorServerMessge;
|
|
|
|
import com.zhonglai.luhui.dao.service.PublicService;
|
|
|
|
import com.zhonglai.luhui.device.domain.IotAlertLog;
|
|
|
|
import io.swagger.annotations.Api;
|
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
|
|
import org.springframework.util.StreamUtils;
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import org.w3c.dom.Document;
|
|
|
|
import org.w3c.dom.Element;
|
|
|
|
import org.w3c.dom.NodeList;
|
|
|
|
import org.xml.sax.InputSource;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
import java.net.URLDecoder;
|
|
|
|
import javax.xml.parsers.DocumentBuilder;
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
import javax.xml.parsers.ParserConfigurationException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.StringReader;
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
import javax.crypto.Cipher;
|
|
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.util.Base64;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
...
|
...
|
@@ -52,6 +57,10 @@ public class ServerController extends BaseController |
|
|
|
{
|
|
|
|
@Autowired
|
|
|
|
private PublicService publicService;
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
private ScheduledExecutorService scheduledExecutorService;
|
|
|
|
|
|
|
|
@ApiOperation("获取详情")
|
|
|
|
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
|
|
|
|
@GetMapping()
|
|
...
|
...
|
@@ -93,104 +102,80 @@ public class ServerController extends BaseController |
|
|
|
return AjaxResult.success();
|
|
|
|
}
|
|
|
|
@ApiOperation("企业微信消息")
|
|
|
|
@RequestMapping("/uploadWxMessage/{agentId}")
|
|
|
|
public AjaxResult uploadWxMessage(@PathVariable String agentId)
|
|
|
|
@RequestMapping("/uploadWxMessage/{sCorpID}")
|
|
|
|
public String uploadWxMessage(@PathVariable String sCorpID, HttpServletRequest httpServletRequest)
|
|
|
|
{
|
|
|
|
|
|
|
|
return AjaxResult.success();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void main(String[] args) throws UnsupportedEncodingException {
|
|
|
|
String TOKEN = "DDbVb3cSiTAbCSgI4UndPlvy"; // 替换为你的token
|
|
|
|
String ENCODING_AES_KEY = "FH1CDpqZhNkcXCWEYJOyAO4HLG2mxYrE1c4j83mXruB";
|
|
|
|
String msgSignature = "6cfbf56d42c00a182a6da650023ef5ba407cb203";
|
|
|
|
String timestamp = "1724921459";
|
|
|
|
String nonce = "1725665565";
|
|
|
|
String echoStr = "FQYmaDL0vzQPBz5rRVYYGVLx62EmD8krbPYO6RzVaAtsIuFz+n8nPZ8fPtnNTbMCiGaRrjZCYgbsaeDcqPqvNQ\u003d\u003d";
|
|
|
|
|
|
|
|
// URL解码
|
|
|
|
String decodedEchoStr = decodeEchoStr(echoStr);
|
|
|
|
|
|
|
|
// 校验msg_signature
|
|
|
|
boolean isValid = validateMsgSignature(TOKEN, timestamp, nonce, decodedEchoStr, msgSignature);
|
|
|
|
if (isValid) {
|
|
|
|
System.out.println("请求合法");
|
|
|
|
} else {
|
|
|
|
System.out.println("请求不合法");
|
|
|
|
}
|
|
|
|
|
|
|
|
// 解密echostr
|
|
|
|
String messageContent = decryptEchoStr(decodedEchoStr,ENCODING_AES_KEY);
|
|
|
|
System.out.println("消息内容: " + messageContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String decodeEchoStr(String echoStr) throws UnsupportedEncodingException {
|
|
|
|
// 假设echoStr已经被Base64编码过,这里直接返回
|
|
|
|
return URLDecoder.decode(echoStr, "UTF-8"); // 实际上需要根据情况解码
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean validateMsgSignature(String token, String timestamp, String nonce, String msgEncrypt, String msgSignature) {
|
|
|
|
String sToken = "JC52PriN";
|
|
|
|
String sEncodingAESKey = "U8Ofa8HdXHlZdg6qVPOg0GurYC35Tufhs11K612Uy5b";
|
|
|
|
WXBizMsgCrypt wxcpt = null;
|
|
|
|
try {
|
|
|
|
String signature = sha1(Arrays.asList(token, timestamp, nonce, msgEncrypt).stream().sorted().collect(Collectors.joining()));
|
|
|
|
return msgSignature.equals(signature);
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String sha1(String input) throws NoSuchAlgorithmException {
|
|
|
|
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
|
|
|
|
byte[] result = mDigest.digest(input.getBytes());
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
for (byte aResult : result) {
|
|
|
|
sb.append(Integer.toString((aResult & 0xff) + 0x100, 16).substring(1));
|
|
|
|
}
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
private static final String CORPID = "wx5823bf96d3bd56c7";
|
|
|
|
private static String decryptEchoStr(String encryptedMsg,String ENCODING_AES_KEY) {
|
|
|
|
// 这里需要实现具体的解密逻辑
|
|
|
|
try {
|
|
|
|
// 1. BASE64解码
|
|
|
|
byte[] base64Decoded = Base64.getDecoder().decode(encryptedMsg);
|
|
|
|
|
|
|
|
// 2. AES解密
|
|
|
|
byte[] keyBytes = Base64.getDecoder().decode(ENCODING_AES_KEY + "=");
|
|
|
|
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
|
|
|
|
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes, 0, 16); // 使用前16个字节作为IV
|
|
|
|
|
|
|
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
|
|
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
|
|
|
|
|
|
|
byte[] decrypted = cipher.doFinal(base64Decoded);
|
|
|
|
|
|
|
|
// 3. 去除随机字节和msg_len
|
|
|
|
byte[] content = Arrays.copyOfRange(decrypted, 16, decrypted.length);
|
|
|
|
int msgLen = ((content[0] & 0xFF) << 24) |
|
|
|
|
((content[1] & 0xFF) << 16) |
|
|
|
|
((content[2] & 0xFF) << 8) |
|
|
|
|
(content[3] & 0xFF);
|
|
|
|
|
|
|
|
byte[] msg = Arrays.copyOfRange(content, 4, 4 + msgLen);
|
|
|
|
byte[] receiveId = Arrays.copyOfRange(content, 4 + msgLen, content.length);
|
|
|
|
|
|
|
|
// 4. 转换为字符串
|
|
|
|
String msgStr = new String(msg, "UTF-8");
|
|
|
|
String receiveIdStr = new String(receiveId, "UTF-8");
|
|
|
|
|
|
|
|
// 5. 验证receiveId
|
|
|
|
if (receiveIdStr.equals(CORPID)) {
|
|
|
|
return msgStr;
|
|
|
|
} else {
|
|
|
|
throw new IllegalArgumentException("ReceiveId 不匹配");
|
|
|
|
wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
|
|
|
|
|
|
|
|
switch (httpServletRequest.getMethod().toUpperCase())
|
|
|
|
{
|
|
|
|
case "GET":
|
|
|
|
String sVerifyMsgSig = httpServletRequest.getParameter("msg_signature");
|
|
|
|
String sVerifyTimeStamp = httpServletRequest.getParameter("timestamp");
|
|
|
|
String sVerifyNonce = httpServletRequest.getParameter("nonce");
|
|
|
|
String sVerifyEchoStr = httpServletRequest.getParameter("echostr");
|
|
|
|
String sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
|
|
|
|
sVerifyNonce, sVerifyEchoStr);
|
|
|
|
return sEchoStr;
|
|
|
|
case "POST":
|
|
|
|
String sReqMsgSig = httpServletRequest.getParameter("msg_signature");
|
|
|
|
String sReqTimeStamp = httpServletRequest.getParameter("timestamp");
|
|
|
|
String sReqNonce = httpServletRequest.getParameter("nonce");
|
|
|
|
String sReqData = new String(StreamUtils.copyToByteArray(httpServletRequest.getInputStream()));
|
|
|
|
|
|
|
|
String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData);
|
|
|
|
System.out.println("after decrypt msg: " + sMsg);
|
|
|
|
|
|
|
|
// TODO: 解析出明文xml标签的内容进行处理
|
|
|
|
// For example:
|
|
|
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
|
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
|
|
StringReader sr = new StringReader(sMsg);
|
|
|
|
InputSource is = new InputSource(sr);
|
|
|
|
Document document = db.parse(is);
|
|
|
|
|
|
|
|
Element root = document.getDocumentElement();
|
|
|
|
NodeList nodelist1 = root.getElementsByTagName("Content");
|
|
|
|
String Content = nodelist1.item(0).getTextContent();
|
|
|
|
System.out.println("Content:" + Content);
|
|
|
|
|
|
|
|
NodeList nodelist2 = root.getElementsByTagName("FromUserName");
|
|
|
|
String FromUserName = nodelist2.item(0).getTextContent();
|
|
|
|
System.out.println("FromUserName:" + FromUserName);
|
|
|
|
|
|
|
|
NodeList nodelist3 = root.getElementsByTagName("AgentID");
|
|
|
|
String AgentID = nodelist3.item(0).getTextContent();
|
|
|
|
System.out.println("AgentID:" + AgentID);
|
|
|
|
|
|
|
|
logger.info("接收到消息:{}",Content);
|
|
|
|
|
|
|
|
scheduledExecutorService.schedule(SendSysMonitorServerMessge.createSendConmmd(publicService,FromUserName,Content,Integer.parseInt(AgentID)),0, TimeUnit.SECONDS);
|
|
|
|
|
|
|
|
return AjaxResult.success().toString();
|
|
|
|
default:
|
|
|
|
return AjaxResult.success().toString();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
|
|
} catch (AesException e) {
|
|
|
|
logger.error("企业微信消息错误",e);
|
|
|
|
return null;
|
|
|
|
} catch (IOException e) {
|
|
|
|
logger.error("消息解码失败",e);
|
|
|
|
return null;
|
|
|
|
} catch (ParserConfigurationException e) {
|
|
|
|
logger.error("消息解析失败",e);
|
|
|
|
return null;
|
|
|
|
} catch (SAXException e) {
|
|
|
|
logger.error("消息解析失败",e);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ApiOperation("获取状态列表")
|
|
|
|
@GetMapping("/getSysMonitorServerList")
|
|
|
|
public TableDataInfo getSysMonitorServerList(SysMonitorServer sysMonitorServer) throws Exception
|
...
|
...
|
|