diff --git a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/controller/ComponentVerifyTicketController.java b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/controller/ComponentVerifyTicketController.java index 6f73d5422c..7a19d3a8e6 100644 --- a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/controller/ComponentVerifyTicketController.java +++ b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/controller/ComponentVerifyTicketController.java @@ -1,11 +1,13 @@ package com.epmet.controller; -import com.epmet.constant.ModuleConstant; import com.epmet.service.ComponentVerifyTicketService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * @Author zxc @@ -20,20 +22,11 @@ public class ComponentVerifyTicketController { private ComponentVerifyTicketService componentVerifyTicketService; /** - * @Description 获取验证票据 - * @param timestamp - * @param nonce - * @param msgSignature - * @param postData + * @Description 获取验证票据3 * @author zxc */ @PostMapping(value = "/callback") - public String componentVerifyTicket(@RequestParam("timestamp") String timestamp, - @RequestParam("nonce") String nonce, - @RequestParam("msg_signature") String msgSignature, - @RequestBody String postData) { - log.info("timestamp = "+timestamp,"nonce = "+nonce,"msgSignature = "+msgSignature,"postData = "+postData); - componentVerifyTicketService.componentVerifyTicket(timestamp,nonce,msgSignature,postData); - return "success"; + public String componentVerifyTicket(HttpServletRequest request, HttpServletResponse response) { + return componentVerifyTicketService.componentVerifyTicket(request,response); } } diff --git a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/ComponentVerifyTicketService.java b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/ComponentVerifyTicketService.java index 0a46086c1f..6178dd929d 100644 --- a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/ComponentVerifyTicketService.java +++ b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/ComponentVerifyTicketService.java @@ -1,5 +1,6 @@ package com.epmet.service; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** @@ -10,15 +11,10 @@ public interface ComponentVerifyTicketService { /** * 获得授权事件的票据 - * - * @param timestamp 时间戳 - * @param nonce 随机数 - * @param msgSignature 消息体签名 - * @param postData 消息体 * @return 如果获得只需要返回 SUCCESS * @Author zxc */ - void componentVerifyTicket(String timestamp,String nonce,String msgSignature,String postData); + String componentVerifyTicket(HttpServletRequest request, HttpServletResponse response); /** * @Description 定时获取 (令牌,component_access_token) diff --git a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/impl/ComponentVerifyTicketServiceImpl.java b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/impl/ComponentVerifyTicketServiceImpl.java index 5ec14b22bd..604ccd06f5 100644 --- a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/impl/ComponentVerifyTicketServiceImpl.java +++ b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/service/impl/ComponentVerifyTicketServiceImpl.java @@ -2,26 +2,28 @@ package com.epmet.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.nacos.client.config.utils.IOUtils; import com.epmet.commons.tools.constant.NumConstant; import com.epmet.commons.tools.utils.HttpClientManager; import com.epmet.constant.ModuleConstant; -import com.epmet.constant.ThirdPlatformConstant; import com.epmet.dao.ComponentVerifyTicketDao; import com.epmet.dto.form.ComponentVerifyTicketFormDTO; import com.epmet.dto.result.AuthorizationInfoResultDTO; -import com.epmet.exception.AesException; import com.epmet.redis.RedisThird; import com.epmet.service.ComponentVerifyTicketService; import com.epmet.util.WXBizMsgCrypt; import com.epmet.util.WXXmlToMapUtil; +import com.epmet.util.XmlUtil; +import com.github.pagehelper.util.StringUtil; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -48,31 +50,64 @@ public class ComponentVerifyTicketServiceImpl implements ComponentVerifyTicketSe */ @Transactional(rollbackFor = Exception.class) @Override - public void componentVerifyTicket(String timeStamp,String nonce,String msgSignature,String postData) { + public String componentVerifyTicket(HttpServletRequest request, HttpServletResponse response) { log.info(ModuleConstant.START_RECEIVE); try { - //这个类是微信官网提供的解密类,需要用到消息校验Token 消息加密Key和服务平台appid - WXBizMsgCrypt pc = new WXBizMsgCrypt(ThirdPlatformConstant.PLATFORM_COMPONENT_TOKEN, ThirdPlatformConstant.PLATFORM_AES_KEY, ThirdPlatformConstant.PLATFORM_APP_ID); - String xml = pc.decryptMsg(msgSignature, timeStamp, nonce, postData); - // 将xml转为map - Map result = WXXmlToMapUtil.xmlToMap(xml); - String componentVerifyTicket = MapUtils.getString(result, ModuleConstant.TICKET_KEY); - if (StringUtils.isNotEmpty(componentVerifyTicket)) { - // 缓存 ticket - redisThird.setComponentVerifyTicket(componentVerifyTicket); - // 存数据库 - ComponentVerifyTicketFormDTO ticketFormDTO = new ComponentVerifyTicketFormDTO(); - ticketFormDTO.setAppid(PLATFORM_APP_ID); - ticketFormDTO.setComponentVerifyTicket(componentVerifyTicket); - ticketDao.insertComponentVerifyTicket(ticketFormDTO); + request.setCharacterEncoding("UTF-8"); + response.setCharacterEncoding("UTF-8"); + // 微信加密签名 + String msgSignature = request.getParameter("msg_signature"); + // 时间戳 + String timeStamp = request.getParameter("timestamp"); + // 随机数 + String nonce = request.getParameter("nonce"); + // 从请求中读取整个post数据 + InputStream inputStream; + String postData = null; + inputStream = request.getInputStream(); + postData= IOUtils.toString(inputStream, "UTF-8"); + //从XML中获取标签内的密文文本 + String encrypt = XmlUtil.toXml(postData); + log.info("Encrypt:"+encrypt); + //格式化密文文本,否则没有标签,会解密失败,参考官方的加解密代码JAVA版本 + String format = ""; + String fromXML = String.format(format, encrypt); + + String msg = ""; //解密后的明文 + WXBizMsgCrypt wxcpt; + if(StringUtil.isEmpty(encrypt)) { + msg = fromXML; } else { - log.error(ModuleConstant.ERROR_TICKET); - throw new RuntimeException(ModuleConstant.ERROR_TICKET); + wxcpt = new WXBizMsgCrypt(PLATFORM_COMPONENT_TOKEN,PLATFORM_AES_KEY, PLATFORM_APP_ID); + // 解密消息 + msg = wxcpt.decryptMsg(msgSignature, timeStamp, nonce, fromXML); } - } catch (AesException e) { - e.printStackTrace(); + log.info("msg:"+msg); + // 将xml转为map + Map result = WXXmlToMapUtil.xmlToMap(msg); + String infotype = result.get("InfoType"); //获取infotype,注:微信开放平台文档中标明固定为:"component_verify_ticket",但参考其他代码,还包含authorized??? + log.info(infotype); + switch (infotype){ + case "component_verify_ticket": //验证票据 + String ComponentVerifyTicket = result.get("ComponentVerifyTicket"); + // 缓存 ticket + redisThird.setComponentVerifyTicket(ComponentVerifyTicket); + // 存数据库 + ComponentVerifyTicketFormDTO ticketFormDTO = new ComponentVerifyTicketFormDTO(); + ticketFormDTO.setAppid(PLATFORM_APP_ID); + ticketFormDTO.setComponentVerifyTicket(ComponentVerifyTicket); + ticketDao.insertComponentVerifyTicket(ticketFormDTO); + log.info("component_verify_ticket:"+ComponentVerifyTicket); + break; + case "unauthorized"://用户取消授权 + return ""; + } + } catch (Exception e) { + log.error(e.getMessage()); + return ""; } log.info(ModuleConstant.END_TICKET); + return "success"; } /** diff --git a/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/util/XmlUtil.java b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/util/XmlUtil.java new file mode 100644 index 0000000000..1fdc3d0307 --- /dev/null +++ b/epmet-module/epmet-third/epmet-third-server/src/main/java/com/epmet/util/XmlUtil.java @@ -0,0 +1,172 @@ +package com.epmet.util; +import com.google.common.collect.Lists; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.QuickWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.CompactWriter; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; +import com.thoughtworks.xstream.io.xml.XppDriver; + +import java.io.StringWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class XmlUtil { + + /** + * 转换不带CDDATA的XML + * + * @return + * @ + */ + private static XStream getXStream() { + // 实例化XStream基本对象 + XStream xstream = new XStream(new DomDriver(StandardCharsets.UTF_8.name(), new NoNameCoder() { + // 不对特殊字符进行转换,避免出现重命名字段时的“双下划线” + @Override + public String encodeNode(String name) { + return name; + } + })); + // 忽视XML与JAVABEAN转换时,XML中的字段在JAVABEAN中不存在的部分 + xstream.ignoreUnknownElements(); + return xstream; + } + + + + /** + * 转换带CDDATA的XML + * + * @return + * @ + */ + private static XStream getXStreamWithCData(List ignoreCDATA) { + // 实例化XStream扩展对象 + XStream xstream = new XStream(new XppDriver() { + // 扩展xstream,使其支持CDATA块 + @Override + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out) { + boolean cdata = true; + // 不对特殊字符进行转换,避免出现重命名字段时的“双下划线” + @Override + public String encodeNode(String name) { + if(!ignoreCDATA.isEmpty()){ + for(String str:ignoreCDATA){ + if(str.equals(name)){ + cdata=false; + return name; + } + } + } + cdata=true; + return name; + } + // 对xml节点的转换都增加CDATA标记 + @Override + protected void writeText(QuickWriter writer, String text) { + if (cdata) { + writer.write(""); + } else { + writer.write(text); + } + } + + + }; + } + }); + // 忽视XML与JAVABEAN转换时,XML中的字段在JAVABEAN中不存在的部分 + xstream.ignoreUnknownElements(); + return xstream; + } + + /** + * 以压缩的方式输出XML + * + * @param obj + * @return + */ + public static String toCompressXml(Object obj) { + XStream xstream = getXStream(); + StringWriter sw = new StringWriter(); + // 识别obj类中的注解 + xstream.processAnnotations(obj.getClass()); + // 设置JavaBean的类别名 + xstream.aliasType("xml", obj.getClass()); + xstream.marshal(obj, new CompactWriter(sw)); + return sw.toString(); + } + + /** + * 以格式化的方式输出XML + * + * @param obj + * @return + */ + public static String toXml(Object obj) { + XStream xstream = getXStream(); + // 识别obj类中的注解 + xstream.processAnnotations(obj.getClass()); + // 设置JavaBean的类别名 + xstream.aliasType("xml", obj.getClass()); + return xstream.toXML(obj); + } + + /** + * 转换成JavaBean + * + * @param xmlStr + * @param cls + * @return + */ + @SuppressWarnings("unchecked") + public static T toBean(String xmlStr, Class cls) { + XStream xstream = getXStream(); + // 识别cls类中的注解 + xstream.processAnnotations(cls); + // 设置JavaBean的类别名 + xstream.aliasType("xml", cls); + T t = (T) xstream.fromXML(xmlStr); + return t; + } + + /** + * 以格式化的方式输出XML + * + * @param obj + * @return + */ + public static String toXmlWithCData(Object obj,List ignoreCDAA) { + XStream xstream = getXStreamWithCData(ignoreCDAA); + // 识别obj类中的注解 + xstream.processAnnotations(obj.getClass()); + // 设置JavaBean的类别名 + xstream.aliasType("xml", obj.getClass()); + return xstream.toXML(obj); + } + + /** + * 转换成JavaBean + * + * @param xmlStr + * @param cls + * @return + */ + @SuppressWarnings("unchecked") + public static T toBeanWithCData(String xmlStr, Class cls) { + XStream xstream = getXStreamWithCData(null); + // 识别cls类中的注解 + xstream.processAnnotations(cls); + // 设置JavaBean的类别名 + xstream.alias("xml", cls); + T t = (T) xstream.fromXML(xmlStr); + return t; + } +}