MsgInterceptor.java 4.9 KB
Newer Older
如梦技术's avatar
v1.3.0  
如梦技术 已提交
1 2
package net.dreamlu.weixin.spring;

3
import com.jfinal.kit.HashKit;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
4 5
import com.jfinal.kit.StrKit;
import com.jfinal.weixin.sdk.api.ApiConfigKit;
6 7
import com.jfinal.wxaapp.WxaConfigKit;
import lombok.RequiredArgsConstructor;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
8
import net.dreamlu.weixin.annotation.WxApi;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
9
import net.dreamlu.weixin.properties.DreamWeixinProperties;
如梦技术's avatar
如梦技术 已提交
10 11
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
12
import org.springframework.core.annotation.AnnotationUtils;
13
import org.springframework.util.StringUtils;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
14 15 16 17 18
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
19
import java.util.Arrays;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
20

21 22 23 24 25 26
/**
 * 消息拦截器
 *
 * @author L.cm
 */
@RequiredArgsConstructor
如梦技术's avatar
v1.3.0  
如梦技术 已提交
27
public class MsgInterceptor extends HandlerInterceptorAdapter {
如梦技术's avatar
如梦技术 已提交
28 29
	private static final Log logger = LogFactory.getLog(MsgInterceptor.class);
	private final DreamWeixinProperties weixinProperties;
如梦技术's avatar
v1.3.0  
如梦技术 已提交
30

如梦技术's avatar
如梦技术 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		// 非控制器请求直接跳出
		if (!(handler instanceof HandlerMethod)) {
			return true;
		}
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		// 如果是 api 接口
		Class<?> beanType = handlerMethod.getBeanType();
		// 处理接口业务
		WxApi wxApi = AnnotationUtils.getAnnotation(beanType, WxApi.class);
		String appId = request.getParameter(weixinProperties.getAppIdKey());
		if (wxApi != null) {
44 45 46
			if (StringUtils.hasText(appId)) {
				ApiConfigKit.setThreadLocalAppId(appId);
			}
如梦技术's avatar
如梦技术 已提交
47 48
			return true;
		}
49
		// 判断是否多公众号,将 appId 与当前线程绑定,以便在后续操作中方便获取ApiConfig对象:
如梦技术's avatar
如梦技术 已提交
50
		Object bean = handlerMethod.getBean();
51 52 53
		boolean isWx = bean instanceof MsgController;
		String token;
		if (isWx) {
54 55 56 57 58 59
			if (StringUtils.hasText(appId)) {
				ApiConfigKit.setThreadLocalAppId(appId);
				token = ApiConfigKit.getApiConfig(appId).getToken();
			} else {
				token = ApiConfigKit.getApiConfig().getToken();
			}
60
		} else {
61
			if (StringUtils.hasText(appId)) {
如梦技术's avatar
如梦技术 已提交
62
				WxaConfigKit.setThreadLocalAppId(appId);
63 64 65 66
				token = WxaConfigKit.getWxaConfig(appId).getToken();
			} else {
				token = WxaConfigKit.getWxaConfig().getToken();
			}
如梦技术's avatar
如梦技术 已提交
67 68 69
		}
		// 如果是服务器配置请求,则配置服务器并返回
		if (isConfigServerRequest(request)) {
70
			configServer(request, response, token);
如梦技术's avatar
如梦技术 已提交
71 72 73 74 75 76 77
			return false;
		}
		// 对开发测试更加友好
		if (ApiConfigKit.isDevMode()) {
			return true;
		} else {
			// 签名检测
78
			if (checkSignature(request, token)) {
如梦技术's avatar
如梦技术 已提交
79 80 81 82 83 84
				return true;
			} else {
				WebUtils.renderText(response, "签名验证失败,请确定是微信服务器在发送消息过来");
				return false;
			}
		}
如梦技术's avatar
v1.3.0  
如梦技术 已提交
85

如梦技术's avatar
如梦技术 已提交
86
	}
如梦技术's avatar
v1.3.0  
如梦技术 已提交
87

如梦技术's avatar
如梦技术 已提交
88 89 90
	/**
	 * 检测签名
	 */
91
	private boolean checkSignature(HttpServletRequest request, String token) {
如梦技术's avatar
如梦技术 已提交
92 93 94 95 96 97 98
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		if (StrKit.isBlank(signature) || StrKit.isBlank(timestamp) || StrKit.isBlank(nonce)) {
			logger.error("check signature failure");
			return false;
		}
99
		if (checkSignature(token, signature, timestamp, nonce)) {
如梦技术's avatar
如梦技术 已提交
100 101 102 103 104 105 106 107 108
			return true;
		} else {
			logger.error("check signature failure: " +
				" signature = " + signature +
				" timestamp = " + timestamp +
				" nonce = " + nonce);
			return false;
		}
	}
如梦技术's avatar
v1.3.0  
如梦技术 已提交
109

如梦技术's avatar
如梦技术 已提交
110 111 112 113 114 115
	/**
	 * 是否为开发者中心保存服务器配置的请求
	 */
	private boolean isConfigServerRequest(HttpServletRequest request) {
		return StrKit.notBlank(request.getParameter("echostr"));
	}
如梦技术's avatar
v1.3.0  
如梦技术 已提交
116

如梦技术's avatar
如梦技术 已提交
117 118 119 120 121 122
	/**
	 * 配置开发者中心微信服务器所需的 url 与 token
	 *
	 * @param request  HttpServletRequest
	 * @param response HttpServletResponse
	 */
123
	private void configServer(HttpServletRequest request, HttpServletResponse response, String token) {
如梦技术's avatar
如梦技术 已提交
124 125 126 127 128
		// 通过 echostr 判断请求是否为配置微信服务器回调所需的 url 与 token
		String echostr = request.getParameter("echostr");
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
129
		boolean isOk = checkSignature(token, signature, timestamp, nonce);
如梦技术's avatar
如梦技术 已提交
130 131 132 133 134 135
		if (isOk && !response.isCommitted()) {
			WebUtils.renderText(response, echostr);
		} else {
			logger.error("验证失败:configServer");
		}
	}
如梦技术's avatar
v1.3.0  
如梦技术 已提交
136

137 138 139 140 141 142 143 144
	private boolean checkSignature(String token, String signature, String timestamp, String nonce) {
		String[] array = new String[]{token, timestamp, nonce};
		Arrays.sort(array);
		String tempStr = array[0] + array[1] + array[2];
		tempStr = HashKit.sha1(tempStr);
		return tempStr.equalsIgnoreCase(signature);
	}

如梦技术's avatar
如梦技术 已提交
145
	@Override
146
	public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
如梦技术's avatar
如梦技术 已提交
147
		ApiConfigKit.removeThreadLocalAppId();
148
		WxaConfigKit.removeThreadLocalAppId();
如梦技术's avatar
如梦技术 已提交
149
	}
150

如梦技术's avatar
v1.3.0  
如梦技术 已提交
151
}