diff --git a/cloud-common-wechat/pom.xml b/cloud-common-wechat/pom.xml
new file mode 100644
index 0000000..efc2849
--- /dev/null
+++ b/cloud-common-wechat/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ cm-cloud
+ com.cm
+ 1.0.1-SNAPSHOT
+
+ 4.0.0
+
+ cloud-common-wechat
+
+
+
+ com.cm
+ cloud-common
+ 1.0.1-SNAPSHOT
+
+
+
+
\ No newline at end of file
diff --git a/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/WechatFilterConfig.java b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/WechatFilterConfig.java
new file mode 100644
index 0000000..8bb9ed7
--- /dev/null
+++ b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/WechatFilterConfig.java
@@ -0,0 +1,31 @@
+package com.cm.common.wechat.config;
+
+import com.cm.common.wechat.filter.WechatFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * When you feel like quitting. Think about why you started
+ * 当你想要放弃的时候,想想当初你为何开始
+ *
+ * @ClassName: WechatFilterConfig
+ * @Description: 微信过滤器
+ * @Author: WangGeng
+ * @Date: 2020/3/2 11:24 下午
+ * @Version: 1.0
+ **/
+@Configuration
+public class WechatFilterConfig {
+
+ @Bean
+ public FilterRegistrationBean wechatFilterRegister() {
+ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
+ filterRegistrationBean.setFilter(new WechatFilter());
+ filterRegistrationBean.addUrlPatterns("/wechat/**", "/wechatroute/**");
+ filterRegistrationBean.setName("wechatFilter");
+ filterRegistrationBean.setOrder(2);
+ return filterRegistrationBean;
+ }
+
+}
diff --git a/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountAuthorizeProperties.java b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountAuthorizeProperties.java
new file mode 100644
index 0000000..6d0b1ea
--- /dev/null
+++ b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountAuthorizeProperties.java
@@ -0,0 +1,89 @@
+package com.cm.common.wechat.config.pojo;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * When you feel like quitting. Think about why you started
+ * 当你想要放弃的时候,想想当初你为何开始
+ *
+ * @ClassName: WechatOfficialAccountAuthorizeProperties
+ * @Description: 微信公众号授权配置
+ * @Author: WangGeng
+ * @Date: 2020/3/2 3:15 下午
+ * @Version: 1.0
+ **/
+public class WechatOfficialAccountAuthorizeProperties {
+ private String authorizeUrl;
+ private String accessTokenUrl;
+ private String accessTokenRefreshUrl;
+ private String userinfoUrl;
+ private String responseType;
+ private String scope;
+ private String state;
+ private String grantType;
+
+ public String getAuthorizeUrl() {
+ return authorizeUrl == null ? "" : authorizeUrl.trim();
+ }
+
+ public void setAuthorizeUrl(String authorizeUrl) {
+ this.authorizeUrl = authorizeUrl;
+ }
+
+ public String getAccessTokenUrl() {
+ return accessTokenUrl == null ? "" : accessTokenUrl.trim();
+ }
+
+ public void setAccessTokenUrl(String accessTokenUrl) {
+ this.accessTokenUrl = accessTokenUrl;
+ }
+
+ public String getAccessTokenRefreshUrl() {
+ return accessTokenRefreshUrl == null ? "" : accessTokenRefreshUrl.trim();
+ }
+
+ public void setAccessTokenRefreshUrl(String accessTokenRefreshUrl) {
+ this.accessTokenRefreshUrl = accessTokenRefreshUrl;
+ }
+
+ public String getUserinfoUrl() {
+ return userinfoUrl == null ? "" : userinfoUrl.trim();
+ }
+
+ public void setUserinfoUrl(String userinfoUrl) {
+ this.userinfoUrl = userinfoUrl;
+ }
+
+ public String getResponseType() {
+ return responseType == null ? "" : responseType.trim();
+ }
+
+ public void setResponseType(String responseType) {
+ this.responseType = responseType;
+ }
+
+ public String getScope() {
+ return scope == null ? "" : scope.trim();
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public String getState() {
+ return state == null ? "" : state.trim();
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getGrantType() {
+ return grantType == null ? "" : grantType.trim();
+ }
+
+ public void setGrantType(String grantType) {
+ this.grantType = grantType;
+ }
+}
diff --git a/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountProperties.java b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountProperties.java
new file mode 100644
index 0000000..d5a56a3
--- /dev/null
+++ b/cloud-common-wechat/src/main/java/com/cm/common/wechat/config/pojo/WechatOfficialAccountProperties.java
@@ -0,0 +1,66 @@
+package com.cm.common.wechat.config.pojo;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+/**
+ * When you feel like quitting. Think about why you started
+ * 当你想要放弃的时候,想想当初你为何开始
+ *
+ * @ClassName: WechatProperties
+ * @Description: 微信配置
+ * @Author: WangGeng
+ * @Date: 2020/3/1 2:22 下午
+ * @Version: 1.0
+ **/
+@Configuration
+@ConfigurationProperties(prefix = "open-platform.wechat.official-account")
+public class WechatOfficialAccountProperties {
+
+ private WechatOfficialAccountAuthorizeProperties authorize;
+ private String accessTokenUrl;
+ private String appId;
+ private String appSecret;
+ private String grantType;
+
+ public WechatOfficialAccountAuthorizeProperties getAuthorize() {
+ return authorize;
+ }
+
+ public void setAuthorize(WechatOfficialAccountAuthorizeProperties authorize) {
+ this.authorize = authorize;
+ }
+
+ public String getAccessTokenUrl() {
+ return accessTokenUrl == null ? "" : accessTokenUrl.trim();
+ }
+
+ public void setAccessTokenUrl(String accessTokenUrl) {
+ this.accessTokenUrl = accessTokenUrl;
+ }
+
+ public String getAppId() {
+ return appId == null ? "" : appId.trim();
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getAppSecret() {
+ return appSecret == null ? "" : appSecret.trim();
+ }
+
+ public void setAppSecret(String appSecret) {
+ this.appSecret = appSecret;
+ }
+
+ public String getGrantType() {
+ return grantType == null ? "" : grantType.trim();
+ }
+
+ public void setGrantType(String grantType) {
+ this.grantType = grantType;
+ }
+}
diff --git a/cloud-common-wechat/src/main/java/com/cm/common/wechat/filter/WechatFilter.java b/cloud-common-wechat/src/main/java/com/cm/common/wechat/filter/WechatFilter.java
new file mode 100644
index 0000000..7d03010
--- /dev/null
+++ b/cloud-common-wechat/src/main/java/com/cm/common/wechat/filter/WechatFilter.java
@@ -0,0 +1,54 @@
+package com.cm.common.wechat.filter;
+
+import com.cm.common.constants.ISystemConstant;
+import com.cm.common.wechat.manager.officialaccount.WechatOfficialAccountManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * When you feel like quitting. Think about why you started
+ * 当你想要放弃的时候,想想当初你为何开始
+ *
+ * @ClassName: WechatFilter
+ * @Description: 微信过滤器
+ * @Author: WangGeng
+ * @Date: 2020/3/1 11:25 上午
+ * @Version: 1.0
+ **/
+public class WechatFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WechatFilter.class);
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+ String requestUri = request.getRequestURI();
+ // 如果参数都存在,标识从服务器重定向回页面,获取AccessToken后放行
+ String codeParameter = request.getParameter("code");
+ String stateParameter = request.getParameter("state");
+ if (!StringUtils.isEmpty(codeParameter) && !StringUtils.isEmpty(stateParameter)) {
+ try {
+ WechatOfficialAccountManager.getInstance().setUserAccessToken(codeParameter, stateParameter, request.getSession());
+ } catch (Exception e) {
+ LOG.error("设置微信公众号session异常");
+ }
+ return;
+ }
+ // 判断session是否存在
+ Object accessToken = request.getSession().getAttribute(ISystemConstant.SESSION_WECHAT_ACCESS_TOKEN);
+ // session 不存在重定向登录
+ if (StringUtils.isEmpty(accessToken)) {
+ response.sendRedirect(WechatOfficialAccountManager.getInstance().getAuthorizeUrl(requestUri));
+ return;
+ }
+ filterChain.doFilter(request, response);
+ }
+
+}
diff --git a/cloud-common-wechat/src/main/java/com/cm/common/wechat/manager/officialaccount/WechatOfficialAccountManager.java b/cloud-common-wechat/src/main/java/com/cm/common/wechat/manager/officialaccount/WechatOfficialAccountManager.java
new file mode 100644
index 0000000..d4ebb14
--- /dev/null
+++ b/cloud-common-wechat/src/main/java/com/cm/common/wechat/manager/officialaccount/WechatOfficialAccountManager.java
@@ -0,0 +1,207 @@
+package com.cm.common.wechat.manager.officialaccount;
+
+import com.cm.common.constants.ISystemConstant;
+import com.cm.common.exception.SearchException;
+import com.cm.common.exception.WechatAccessTokenException;
+import com.cm.common.exception.WechatAccessTokenForUserException;
+import com.cm.common.exception.WechatUserInfoException;
+import com.cm.common.utils.AesUtil;
+import com.cm.common.utils.http.RestRequestUtil;
+import com.cm.common.wechat.config.pojo.WechatOfficialAccountProperties;
+import com.cm.common.wechat.pojo.WechatOfficialAccountAccessToken;
+import com.cm.common.wechat.pojo.WechatOfficialAccountAccessTokenForUser;
+import com.cm.common.wechat.pojo.WechatOfficialAccountUser;
+import com.cm.common.wechat.pojo.WechatOfficialAccountUserInfo;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import javax.servlet.http.HttpSession;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * When you feel like quitting. Think about why you started
+ * 当你想要放弃的时候,想想当初你为何开始
+ *
+ * @ClassName: WechatOfficialAccountManager
+ * @Description: 公众号管理器
+ * @Author: WangGeng
+ * @Date: 2020/3/1 3:02 下午
+ * @Version: 1.0
+ **/
+public class WechatOfficialAccountManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WechatOfficialAccountManager.class);
+ private static WechatOfficialAccountManager wechatOfficialAccountManager = WechatOfficialAccountManagerBuilder.wechatOfficialAccountManager;
+
+ private WechatOfficialAccountProperties wechatOfficialAccountProperties;
+ private String accessToken;
+ private long updateTime = 0L;
+
+ public static WechatOfficialAccountManager getInstance() {
+ return wechatOfficialAccountManager;
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ /**
+ * 刷新AccessToken,超过1小时30分刷新一次
+ */
+ public void refreshAccessToken() {
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - this.updateTime) >= 5400000) {
+ LOG.debug("刷新公众号 AccessToken 开始");
+ this.accessToken = getNewAccessToken();
+ this.updateTime = System.currentTimeMillis();
+ LOG.debug("刷新公众号 AccessToken 结束");
+ }
+ }
+
+ /**
+ * 获得新AccessToken
+ *
+ * @return
+ */
+ private String getNewAccessToken() {
+ RestTemplate restTemplate = new RestTemplateBuilder().build();
+ Map params = new HashMap<>(3);
+ params.put("grant_type", wechatOfficialAccountProperties.getGrantType());
+ params.put("appid", wechatOfficialAccountProperties.getAppId());
+ params.put("secret", wechatOfficialAccountProperties.getAppSecret());
+ String url = new StringBuilder(wechatOfficialAccountProperties.getAccessTokenUrl()).append("?grant_type={grant_type}&appid={appid}&secret={secret}").toString();
+ WechatOfficialAccountAccessToken wechatOfficialAccountAccessToken = restTemplate.getForObject(url, WechatOfficialAccountAccessToken.class, params);
+ if (wechatOfficialAccountAccessToken == null) {
+ throw new WechatAccessTokenException("获取 AccessToken 失败");
+ }
+ if (wechatOfficialAccountAccessToken.getErrcode() != null && wechatOfficialAccountAccessToken.getErrcode() != 0) {
+ throw new WechatAccessTokenException(String.format("获取AccessToken失败,错误码:%s,错误信息:%s", wechatOfficialAccountAccessToken.getErrcode(), wechatOfficialAccountAccessToken.getErrmsg()));
+ }
+ return wechatOfficialAccountAccessToken.getAccess_token();
+ }
+
+ public void setWechatOfficialAccountProperties(WechatOfficialAccountProperties wechatOfficialAccountProperties) {
+ this.wechatOfficialAccountProperties = wechatOfficialAccountProperties;
+ }
+
+ /**
+ * 重定向url
+ *
+ * @param requestUri
+ * @return
+ */
+ public String getAuthorizeUrl(String requestUri) {
+ StringBuilder authorizeUrl = new StringBuilder(wechatOfficialAccountProperties.getAuthorize().getAuthorizeUrl());
+ authorizeUrl.append("?appid=").append(wechatOfficialAccountProperties.getAppId());
+ authorizeUrl.append("&scope=").append(wechatOfficialAccountProperties.getAuthorize().getScope());
+ authorizeUrl.append("&state=").append(wechatOfficialAccountProperties.getAuthorize().getState());
+ authorizeUrl.append("&redirect_uri=").append(requestUri);
+ authorizeUrl.append("&response_type=code#wechat_redirect");
+ return authorizeUrl.toString();
+ }
+
+ /**
+ * 设置用户信息
+ *
+ * @param code
+ * @param state
+ * @param session
+ */
+ public void setUserAccessToken(String code, String state, HttpSession session) throws Exception {
+ if (!StringUtils.equals(state, wechatOfficialAccountProperties.getAuthorize().getState())) {
+ WechatOfficialAccountAccessTokenForUser wechatOfficialAccountAccessTokenForUser = getUserAccessToken(code);
+ WechatOfficialAccountUserInfo wechatOfficialAccountUserInfo = getUserInfo(wechatOfficialAccountAccessTokenForUser.getAccess_token(), wechatOfficialAccountAccessTokenForUser.getOpenid());
+ WechatOfficialAccountUser wechatOfficialAccountUser = new WechatOfficialAccountUser();
+ // 绑定用户 | 登录
+ String wechatSignInfo = AesUtil.aesCommonEncoder("WECHAT_SIGN_INFO", Base64.encodeBase64String(new StringBuilder(wechatOfficialAccountAccessTokenForUser.getOpenid()).append("_WenG_").append(wechatOfficialAccountProperties.getAppId()).toString().getBytes("UTF-8")));
+ String token = getAppToken(wechatSignInfo);
+ wechatOfficialAccountUser.setToken(token);
+ wechatOfficialAccountUser.setWechatOfficialAccountAccessTokenForUser(wechatOfficialAccountAccessTokenForUser);
+ wechatOfficialAccountUser.setWechatOfficialAccountUserInfo(wechatOfficialAccountUserInfo);
+ session.setAttribute(ISystemConstant.SESSION_WECHAT_ACCESS_TOKEN, wechatOfficialAccountUser);
+ return;
+ }
+ }
+
+ /**
+ * 获取AppToken
+ *
+ * @param wechatSignInfo
+ * @return
+ */
+ public String getAppToken(String wechatSignInfo) {
+ RestTemplate restTemplate = new RestTemplate();
+ Map params = new HashMap<>(1);
+ params.put("signInfo", wechatSignInfo);
+ HttpEntity