package com.foxinmy.weixin4j.socket; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.util.AesToken; import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.ServerToolkits; import com.foxinmy.weixin4j.xml.EncryptMessageHandler; /** * 微信消息解码类 * * @className WeixinMessageDecoder * @author jinyu(foxinmy@gmail.com) * @date 2014年11月13日 * @since JDK 1.6 * @see <a * href="http://mp.weixin.qq.com/wiki/0/61c3a8b9d50ac74f18bdf2e54ddfc4e0.html">加密接入指引</a> * @see com.foxinmy.weixin4j.request.WeixinRequest */ @ChannelHandler.Sharable public class WeixinMessageDecoder extends MessageToMessageDecoder<FullHttpRequest> { private final InternalLogger logger = InternalLoggerFactory .getInstance(getClass()); private Map<String, AesToken> aesTokenMap = new ConcurrentHashMap<String, AesToken>(); public WeixinMessageDecoder(final Map<String, AesToken> aesTokenMap) { for (Entry<String, AesToken> entry : aesTokenMap.entrySet()) { this.aesTokenMap.put(entry.getKey() == null ? "" : entry.getKey(), entry.getValue()); } } public int addAesToken(final AesToken asetoken) { AesToken token = aesTokenMap.get(asetoken.getWeixinId()); if (token != null) return -1; aesTokenMap.put(asetoken.getWeixinId(), asetoken); return 0; } @Override protected void decode(ChannelHandlerContext ctx, FullHttpRequest req, List<Object> out) throws WeixinException { String messageContent = req.content().toString(ServerToolkits.UTF_8); QueryStringDecoder queryDecoder = new QueryStringDecoder(req.uri(), true); HttpMethod method = req.method(); logger.info("decode request:{} use {} method invoking", req.uri(), method); Map<String, List<String>> parameters = queryDecoder.parameters(); EncryptType encryptType = parameters.containsKey("encrypt_type") ? EncryptType .valueOf(parameters.get("encrypt_type").get(0).toUpperCase()) : EncryptType.RAW; String echoStr = parameters.containsKey("echostr") ? parameters.get( "echostr").get(0) : ""; String timeStamp = parameters.containsKey("timestamp") ? parameters .get("timestamp").get(0) : ""; String nonce = parameters.containsKey("nonce") ? parameters .get("nonce").get(0) : ""; String signature = parameters.containsKey("signature") ? parameters .get("signature").get(0) : ""; String msgSignature = parameters.containsKey("msg_signature") ? parameters .get("msg_signature").get(0) : ""; String weixinId = parameters.containsKey("weixin_id") ? parameters.get( "weixin_id").get(0) : ""; AesToken aesToken = aesTokenMap.get(weixinId); String encryptContent = null; if (!ServerToolkits.isBlank(messageContent) && encryptType == EncryptType.AES) { if (ServerToolkits.isBlank(aesToken.getAesKey())) { throw new WeixinException( "EncodingAESKey not be empty in safety(AES) mode"); } EncryptMessageHandler encryptHandler = EncryptMessageHandler .parser(messageContent); encryptContent = encryptHandler.getEncryptContent(); /** * 企业号第三方套件 ╮(╯_╰)╭ */ if (aesToken.getWeixinId().startsWith("tj")) { aesToken = new AesToken(encryptHandler.getToUserName(), aesToken.getToken(), aesToken.getAesKey()); } messageContent = MessageUtil.aesDecrypt(aesToken.getWeixinId(), aesToken.getAesKey(), encryptContent); } logger.info("read original message {}", messageContent); WeixinRequest request = new WeixinRequest(req.headers(), method, req.uri(), encryptType, echoStr, timeStamp, nonce, signature, msgSignature, messageContent, encryptContent, aesToken); request.setDecoderResult(req.decoderResult()); request.setProtocolVersion(req.protocolVersion()); out.add(request); } }