View Javadoc
1   package com.foxinmy.weixin4j.socket;
2   
3   import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
4   import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
5   import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
6   
7   import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
8   import com.foxinmy.weixin4j.request.WeixinRequest;
9   import com.foxinmy.weixin4j.response.SingleResponse;
10  import com.foxinmy.weixin4j.type.EncryptType;
11  import com.foxinmy.weixin4j.util.AesToken;
12  import com.foxinmy.weixin4j.util.HttpUtil;
13  import com.foxinmy.weixin4j.util.MessageUtil;
14  import com.foxinmy.weixin4j.util.ServerToolkits;
15  
16  import io.netty.channel.ChannelFutureListener;
17  import io.netty.channel.ChannelHandlerContext;
18  import io.netty.channel.SimpleChannelInboundHandler;
19  import io.netty.handler.codec.http.DefaultFullHttpResponse;
20  import io.netty.handler.codec.http.FullHttpResponse;
21  import io.netty.handler.codec.http.HttpMethod;
22  import io.netty.handler.codec.http.HttpResponseStatus;
23  import io.netty.util.internal.logging.InternalLogger;
24  import io.netty.util.internal.logging.InternalLoggerFactory;
25  
26  /**
27   * 微信请求处理类
28   *
29   * @className WeixinRequestHandler
30   * @author jinyu(foxinmy@gmail.com)
31   * @date 2014年11月16日
32   * @since JDK 1.6
33   * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher
34   */
35  public class WeixinRequestHandler extends SimpleChannelInboundHandler<WeixinRequest> {
36      private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
37  
38      private final WeixinMessageDispatcher messageDispatcher;
39  
40      public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher) {
41          this.messageDispatcher = messageDispatcher;
42      }
43  
44      public void channelReadComplete(ChannelHandlerContext ctx) {
45          ctx.flush();
46      }
47  
48      @Override
49      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
50          ctx.close();
51          logger.error(cause);
52      }
53  
54      @Override
55      protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) {
56          AesToken aesToken = request.getAesToken();
57          // 消息字段不完整返回400
58          if (aesToken == null || (ServerToolkits.isBlank(request.getSignature())
59                  && ServerToolkits.isBlank(request.getMsgSignature()))) {
60              ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request)).addListener(ChannelFutureListener.CLOSE);
61              return;
62          }
63          /**
64           * 公众平台:无论Get,Post都带signature参数,当开启aes模式时带msg_signature参数
65           * 企业号:无论Get,Post都带msg_signature参数
66           * 一般来说:signature验证url上的参数签名,msg_signature验证消息体签名
67           **/
68          if (request.getMethod() == HttpMethod.GET) {
69              // URL参数签名验证
70              if (!ServerToolkits.isBlank(request.getSignature())
71                      && MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
72                              .equals(request.getSignature())) {
73                  ctx.writeAndFlush(new SingleResponse(request.getEchoStr()));
74                  return;
75              }
76              // XML消息签名验证
77              if (!ServerToolkits.isBlank(request.getMsgSignature()) && MessageUtil
78                      .signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(), request.getEchoStr())
79                      .equals(request.getMsgSignature())) {
80                  ctx.writeAndFlush(
81                          new SingleResponse(MessageUtil.aesDecrypt(null, aesToken.getAesKey(), request.getEchoStr())));
82                  return;
83              }
84              ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
85              return;
86          } else if (request.getMethod() == HttpMethod.POST) {
87              // URL参数签名验证
88              if (!ServerToolkits.isBlank(request.getSignature())
89                      && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
90                              .equals(request.getSignature())) {
91                  ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
92                  return;
93              }
94              // XML消息签名验证
95              if (request.getEncryptType() == EncryptType.AES
96                      && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(),
97                              request.getEncryptContent()).equals(request.getMsgSignature())) {
98                  ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
99                  return;
100             }
101         } else {
102             // 访问其它URL
103             ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)).addListener(ChannelFutureListener.CLOSE);
104             return;
105         }
106         messageDispatcher.doDispatch(ctx, request);
107     }
108 
109     private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, WeixinRequest request) {
110         FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), responseStatus);
111         HttpUtil.resolveHeaders(response);
112         return response;
113     }
114 }