用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)
生活随笔
收集整理的這篇文章主要介紹了
用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? 要搭建加密傳輸的微信公眾號消息傳輸,首先要在開發這平臺下載一下微信加密的相關jar包,并做一些準備。準備的步驟如下:
1.打開開發者文檔,找到消息加減密--->接入指引,如下圖所示:
2.在頁面底部找到實例代碼,并下載解壓,下載的地方如下圖所示:
3.在解壓的地方找到java版本,并做如下準備:
(1)將commons-codec-1.9.jar導入到項目中。
(2)將dist下的aes-jre1.6.jar導入到項目中。
(3)打開readme.txt,按照他的指示操作。紅色對勾的地方很重要。
要下載的東西就是下圖標記的地方
這樣準備工作就完成了,可以進入正式的代碼編寫了。
代碼部分的解釋基本都放在注釋中,首先開用來核心控制的controller。內容如下:
package org.calonlan.soulpower.controller;import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.util.Map;import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.calonlan.soulpower.service.WeiInfoService; import org.calonlan.soulpower.util.AesUtils; import org.calonlan.soulpower.util.MessageUtil; import org.calonlan.soulpower.util.SignUtil; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;/*** @author Administrator* 這個controller是用來處理消息的核心controller,在這里有兩個請求地址都為/sign的請求地址,一個是用get方式,用來* 做服務器和微信服務器之間的認證;一個是post方式,用來在服務器和微信服務器之間傳遞消息。*/ @Controller @RequestMapping("/core") public class CoreController {@Resourceprivate WeiInfoService weiInfoService;/** 這個service大家可以不用管,* 因為在我的項目中我是把所有的微信相關的配置信息都保存在一個weiInfo的類中了* ,這里只會用到token。*//*** @param request* @param response* @throws IOException* @throws ServletException* 用來和微信服務器之間相互認證*/@RequestMapping(method = RequestMethod.GET, value = "/sign")public void goGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException {String signature = request.getParameter("signature");// 獲得signatureString timestamp = request.getParameter("timestamp");// 獲得timestampString nonce = request.getParameter("nonce");// 獲得nonceString echostr = request.getParameter("echostr");// 獲得echostr/** 上面的四個參數都是微信服務器發送過來的,其中signature、timestamp、nonce是要參與服務器的驗證的,* 而echostr是在我們通過驗證后返回給服務器告訴服務器我們就是要通訊 的那個遠程服務器*/PrintWriter out = response.getWriter();if (SignUtil.checkSignature(signature, timestamp, nonce,weiInfoService.get())) {//在SignUtil中使用checkSignature來進行驗證,代碼附在后面。out.print(echostr);//驗證通過后就把echostr返回給微信服務器。}out.close();out = null;}@RequestMapping(method = RequestMethod.POST, value = "/sign")/*** * 用來和微信服務器通信* * */public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");/** 進行消息分發 *//* 首先定義一個空的回復消息 */String respMessage = "";try {/* 從請求中獲得xml格式的信息。并轉化為map類型 */Map<String, String> requestMapSecret = MessageUtil.parseXml(request);//從request中獲得獲得xml,并解析,代碼附在后面/* 獲得解密后的消息正文 */String mingwenXML = AesUtils.descMessage(//用微信官方給的jar包中的AesUtils來對消息進行解密requestMapSecret.get("Encrypt"),/* 加密的消息體 */request.getParameter("msg_signature"),/* 請求中的消息簽名 */request.getParameter("timestamp"),/* 時間戳 */request.getParameter("nonce"));/* 無序數列 *//* 將明文再次進行xml解析 */Map<String, String> requestMap = MessageUtil.parseXml(new StringReader(mingwenXML));//將明文的xml再次解析后放入map中,/** 獲得用戶發來的消息類型,并做相應的處理 */String messageType = requestMap.get("MsgType");System.out.println(messageType);/*處理不同格式的消息類型開始-------------------------------------------------------*/// 用戶發來的是文本消息if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {System.out.println(requestMap.get("Content"));}// 用戶發來的是圖片消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {}// 用戶發來地理位置信息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {}// 用戶發來鏈接消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {}// 用戶發來音頻消息else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {}/** 事件推送的處理 */else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// 事件類型String eventType = requestMap.get("Event");// 訂閱if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_SUBSCRIBE)) {}// 取消訂閱else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_UNSUBSCRIBE)) {}// 點擊按鈕事件else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_CLICK)) {}}/*處理不同格式的消息類型介紹-------------------------------------------------------*//*對于不同類型的消息的處理網上有很多高手已經發表了很多文章了,我自己也會總結一下,不過不是在這里---------*/// 給返回的消息加密AesUtils.aescMessage(respMessage,request.getParameter("timestamp"),request.getParameter("nonce"));} catch (Exception e) {e.printStackTrace();}/*返回消息給微信服務器,然后微信服務器把消息轉發給用戶···額,貌似我們聊什么,微信服務器都是可以截獲的,*/PrintWriter out = response.getWriter();out.print(respMessage);out.close();} }
SignUtil中的checkSignature代碼如下:
public static boolean checkSignature(String signature, String timestamp,String nonce, WeiInfo info) {/** 微信服務器發送過來的signature是通過某些處理然后進行SHA1加密的,我們來用它發過來的信息自己生成一個signature,* 然后兩者之間進行比對,一致的話我們就是伙伴,不一致就拒絕它*/String[] arr = new String[] { info.getToken(), timestamp, nonce };/* token是我們自己填寫的,具體填寫位置見下圖;timestamp、nonce是微信服務器發送過來的,這里我們把他們都放到數組中。*/Arrays.sort(arr);//對數組中的數據進行字典排序。。。。要不然加密出來的東西是沒用的StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}//把字典排序好的數組讀取成字符串。MessageDigest md = null;String tmpStr = null;try {/*進行sha1加密*/md = MessageDigest.getInstance("SHA-1");byte[] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);//將加密后的byte轉化為16進制字符串,這就是我們自己構造的signature} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;//進行對比,相同返回true,不同返回false}private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);//分別把沒一個byte位轉換成一個16進制字符,代碼見下面}return strDigest;}
private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}
AesUtils的具體代碼
MessageUtil中的parseXml代碼,有兩個,一個是用來直接解析request中的xml,一個是用來解析字符串類型的xml
解析request中的xml代碼
public static Map<String, String> parseXml(HttpServletRequest request)throws Exception {Map<String, String> map = new HashMap<String, String>();InputStream inputStream = request.getInputStream();SAXReader reader = new SAXReader();//我用的是SAXReaderDocument document = reader.read(inputStream);Element root = document.getRootElement();@SuppressWarnings("unchecked")List<Element> elementList = root.elements();for (Element e : elementList) {map.put(e.getName(), e.getText());}inputStream.close();inputStream = null;return map;}
到這里,構建就完成了,可以用我們的服務器來和微信服務器進行密文的消息傳遞了。
總結
以上是生活随笔為你收集整理的用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 指针运算不同于算数运算,不能简单加减
- 下一篇: Http长连接的例子_亲测可用哦