完善微信绑定功能
This commit is contained in:
parent
17334c098b
commit
4d0b643f7b
@ -1,6 +1,8 @@
|
||||
package com.cm.common.wechat.config;
|
||||
|
||||
import com.cm.common.wechat.config.pojo.WechatOfficialAccountProperties;
|
||||
import com.cm.common.wechat.filter.WechatFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -18,13 +20,19 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration
|
||||
public class WechatFilterConfig {
|
||||
|
||||
@Autowired
|
||||
private WechatOfficialAccountProperties wechatOfficialAccountProperties;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean wechatFilterRegister() {
|
||||
WechatFilter wechatFilter = new WechatFilter();
|
||||
wechatFilter.setWechatOfficialAccountProperties(wechatOfficialAccountProperties);
|
||||
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
|
||||
filterRegistrationBean.setFilter(new WechatFilter());
|
||||
filterRegistrationBean.addUrlPatterns("/wechat/**", "/wechatroute/**");
|
||||
filterRegistrationBean.setFilter(wechatFilter);
|
||||
filterRegistrationBean.addUrlPatterns("/wechat/*", "/wechatroute/*");
|
||||
filterRegistrationBean.setName("wechatFilter");
|
||||
filterRegistrationBean.setOrder(2);
|
||||
filterRegistrationBean.setOrder(1);
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,11 @@ public class WechatOfficialAccountProperties {
|
||||
|
||||
private WechatOfficialAccountAuthorizeProperties authorize;
|
||||
private String accessTokenUrl;
|
||||
private String bindUserUrl;
|
||||
private String appId;
|
||||
private String appSecret;
|
||||
private String grantType;
|
||||
private String configToken;
|
||||
|
||||
public WechatOfficialAccountAuthorizeProperties getAuthorize() {
|
||||
return authorize;
|
||||
@ -40,6 +42,14 @@ public class WechatOfficialAccountProperties {
|
||||
this.accessTokenUrl = accessTokenUrl;
|
||||
}
|
||||
|
||||
public String getBindUserUrl() {
|
||||
return bindUserUrl == null ? "" : bindUserUrl.trim();
|
||||
}
|
||||
|
||||
public void setBindUserUrl(String bindUserUrl) {
|
||||
this.bindUserUrl = bindUserUrl;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId == null ? "" : appId.trim();
|
||||
}
|
||||
@ -63,4 +73,33 @@ public class WechatOfficialAccountProperties {
|
||||
public void setGrantType(String grantType) {
|
||||
this.grantType = grantType;
|
||||
}
|
||||
|
||||
public String getConfigToken() {
|
||||
return configToken == null ? "" : configToken.trim();
|
||||
}
|
||||
|
||||
public void setConfigToken(String configToken) {
|
||||
this.configToken = configToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
sb.append("\"authorize\":")
|
||||
.append(authorize);
|
||||
sb.append(",\"accessTokenUrl\":")
|
||||
.append("\"").append(accessTokenUrl).append("\"");
|
||||
sb.append(",\"bindUserUrl\":")
|
||||
.append("\"").append(bindUserUrl).append("\"");
|
||||
sb.append(",\"appId\":")
|
||||
.append("\"").append(appId).append("\"");
|
||||
sb.append(",\"appSecret\":")
|
||||
.append("\"").append(appSecret).append("\"");
|
||||
sb.append(",\"grantType\":")
|
||||
.append("\"").append(grantType).append("\"");
|
||||
sb.append(",\"configToken\":")
|
||||
.append("\"").append(configToken).append("\"");
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
package com.cm.common.wechat.controller;
|
||||
|
||||
import com.cm.common.constants.ISystemConstant;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: WechatOfficialAccountTestController
|
||||
* @Description: 微信公众号测试
|
||||
* @Author: WangGeng
|
||||
* @Date: 2020/3/3 12:10 下午
|
||||
* @Version: 1.0
|
||||
**/
|
||||
@Api(tags = ISystemConstant.API_TAGS_WECHAT_PREFIX + "页面测试")
|
||||
@Controller
|
||||
@RequestMapping(ISystemConstant.WECHAT_ROUTE_PREFIX + "/officialaccount")
|
||||
public class WechatOfficialAccountTestRouteController {
|
||||
|
||||
@GetMapping("index")
|
||||
public void index(HttpServletResponse response) throws IOException {
|
||||
Writer writer = response.getWriter();
|
||||
writer.write("<!DOCTYPE html><html><body><h1>Hello World!!!</h1><br/><br/><a href=\"/usercenter/wechatroute/officialaccount/index2\">点击跳转</a></body></html>");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@GetMapping("index2")
|
||||
public void index2(HttpServletResponse response) throws IOException {
|
||||
Writer writer = response.getWriter();
|
||||
writer.write("<!DOCTYPE html><html><body><h1>Config Success</h1><br/><br/><a href=\"/usercenter/wechatroute/officialaccount/index\">返回</a></body></html>");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,25 @@
|
||||
package com.cm.common.wechat.filter;
|
||||
|
||||
import com.cm.common.constants.ISystemConstant;
|
||||
import com.cm.common.wechat.config.pojo.WechatOfficialAccountProperties;
|
||||
import com.cm.common.wechat.manager.officialaccount.WechatOfficialAccountManager;
|
||||
import org.apache.shiro.crypto.hash.Sha1Hash;
|
||||
import org.apache.shiro.crypto.hash.SimpleHash;
|
||||
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
@ -24,12 +34,48 @@ import java.io.IOException;
|
||||
public class WechatFilter implements Filter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WechatFilter.class);
|
||||
private WechatOfficialAccountProperties wechatOfficialAccountProperties;
|
||||
private AntPathMatcher antPathMatcher;
|
||||
|
||||
private static final String WECHAT_LOGIN_URL = "/**/wechat/sign/login";
|
||||
/**
|
||||
* 微信放行接口
|
||||
*/
|
||||
private static final String WECHAT_RELEASE_URL = "/**/wechatrelease/**";
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
antPathMatcher = new AntPathMatcher();
|
||||
}
|
||||
|
||||
@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();
|
||||
if (antPathMatcher.match(WECHAT_LOGIN_URL, requestUri) || antPathMatcher.match(WECHAT_RELEASE_URL, requestUri)) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是不是微信配置校验
|
||||
String signatureParameter = request.getParameter("signature");
|
||||
String timestampParameter = request.getParameter("timestamp");
|
||||
String nonceParameter = request.getParameter("nonce");
|
||||
String echostrParameter = request.getParameter("echostr");
|
||||
boolean isWechatConfig = !StringUtils.isEmpty(signatureParameter)
|
||||
&& !StringUtils.isEmpty(timestampParameter)
|
||||
&& !StringUtils.isEmpty(nonceParameter)
|
||||
&& !StringUtils.isEmpty(echostrParameter);
|
||||
if (isWechatConfig && isWechatOfficialAccountConfigRequest(signatureParameter, timestampParameter, nonceParameter, echostrParameter)) {
|
||||
Writer writer = response.getWriter();
|
||||
writer.write(echostrParameter);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// 绑定校验
|
||||
// 如果参数都存在,标识从服务器重定向回页面,获取AccessToken后放行
|
||||
String codeParameter = request.getParameter("code");
|
||||
String stateParameter = request.getParameter("state");
|
||||
@ -37,18 +83,49 @@ public class WechatFilter implements Filter {
|
||||
try {
|
||||
WechatOfficialAccountManager.getInstance().setUserAccessToken(codeParameter, stateParameter, request.getSession());
|
||||
} catch (Exception e) {
|
||||
LOG.error("设置微信公众号session异常");
|
||||
LOG.error(e.getMessage(), e);
|
||||
response.setStatus(404);
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 判断session是否存在
|
||||
Object accessToken = request.getSession().getAttribute(ISystemConstant.SESSION_WECHAT_ACCESS_TOKEN);
|
||||
// session 不存在重定向登录
|
||||
if (StringUtils.isEmpty(accessToken)) {
|
||||
response.sendRedirect(WechatOfficialAccountManager.getInstance().getAuthorizeUrl(requestUri));
|
||||
response.sendRedirect(WechatOfficialAccountManager.getInstance().getAuthorizeUrl(request.getRequestURL().toString()));
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是来自微信的配置请求
|
||||
*
|
||||
* @param signature
|
||||
* @param timestamp
|
||||
* @param nonce
|
||||
* @param echostr
|
||||
* @return
|
||||
*/
|
||||
private boolean isWechatOfficialAccountConfigRequest(String signature, String timestamp, String nonce, String echostr) {
|
||||
List<String> sortList = new ArrayList<>();
|
||||
sortList.add(wechatOfficialAccountProperties.getConfigToken());
|
||||
sortList.add(timestamp);
|
||||
sortList.add(nonce);
|
||||
Collections.sort(sortList);
|
||||
StringBuilder newSignature = new StringBuilder();
|
||||
sortList.forEach(str -> {
|
||||
newSignature.append(str);
|
||||
});
|
||||
if (!StringUtils.pathEquals(signature, new SimpleHash("SHA-1", newSignature.toString()).toString())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setWechatOfficialAccountProperties(WechatOfficialAccountProperties wechatOfficialAccountProperties) {
|
||||
this.wechatOfficialAccountProperties = wechatOfficialAccountProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ 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;
|
||||
@ -14,6 +13,7 @@ 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.codehaus.jackson.map.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
@ -23,6 +23,7 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -61,6 +62,7 @@ public class WechatOfficialAccountManager {
|
||||
if ((currentTime - this.updateTime) >= 5400000) {
|
||||
LOG.debug("刷新公众号 AccessToken 开始");
|
||||
this.accessToken = getNewAccessToken();
|
||||
LOG.debug("accessToken: {}", this.accessToken);
|
||||
this.updateTime = System.currentTimeMillis();
|
||||
LOG.debug("刷新公众号 AccessToken 结束");
|
||||
}
|
||||
@ -95,15 +97,15 @@ public class WechatOfficialAccountManager {
|
||||
/**
|
||||
* 重定向url
|
||||
*
|
||||
* @param requestUri
|
||||
* @param redirectUrl
|
||||
* @return
|
||||
*/
|
||||
public String getAuthorizeUrl(String requestUri) {
|
||||
public String getAuthorizeUrl(String redirectUrl) {
|
||||
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("&redirect_uri=").append(redirectUrl);
|
||||
authorizeUrl.append("&response_type=code#wechat_redirect");
|
||||
return authorizeUrl.toString();
|
||||
}
|
||||
@ -116,12 +118,12 @@ public class WechatOfficialAccountManager {
|
||||
* @param session
|
||||
*/
|
||||
public void setUserAccessToken(String code, String state, HttpSession session) throws Exception {
|
||||
if (!StringUtils.equals(state, wechatOfficialAccountProperties.getAuthorize().getState())) {
|
||||
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 wechatSignInfo = Base64.encodeBase64String(AesUtil.aesCommonEncoder("WECHAT_SIGN_INFO", new StringBuilder(wechatOfficialAccountAccessTokenForUser.getOpenid()).append("_WenG_").append(wechatOfficialAccountProperties.getAppId()).toString()).getBytes("UTF-8"));
|
||||
String token = getAppToken(wechatSignInfo);
|
||||
wechatOfficialAccountUser.setToken(token);
|
||||
wechatOfficialAccountUser.setWechatOfficialAccountAccessTokenForUser(wechatOfficialAccountAccessTokenForUser);
|
||||
@ -142,7 +144,8 @@ public class WechatOfficialAccountManager {
|
||||
Map<String, Object> params = new HashMap<>(1);
|
||||
params.put("signInfo", wechatSignInfo);
|
||||
HttpEntity<Map<String, Object>> requestBody = new HttpEntity<>(params);
|
||||
ResponseEntity<Map> result = restTemplate.postForEntity("", requestBody, Map.class);
|
||||
ResponseEntity<Map> result = restTemplate.postForEntity(wechatOfficialAccountProperties.getBindUserUrl(), requestBody, Map.class);
|
||||
LOG.debug("状态码:{}", result.getStatusCodeValue());
|
||||
if (HttpStatus.OK.value() != result.getStatusCodeValue()) {
|
||||
throw new SearchException("获取Token失败");
|
||||
}
|
||||
@ -156,16 +159,18 @@ public class WechatOfficialAccountManager {
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
public WechatOfficialAccountAccessTokenForUser getUserAccessToken(String code) {
|
||||
public WechatOfficialAccountAccessTokenForUser getUserAccessToken(String code) throws IOException {
|
||||
Map<String, Object> params = new HashMap<>(4);
|
||||
params.put("appid", wechatOfficialAccountProperties.getAppId());
|
||||
params.put("secret", wechatOfficialAccountProperties.getAppSecret());
|
||||
params.put("code", code);
|
||||
params.put("grant_type", wechatOfficialAccountProperties.getAuthorize().getGrantType());
|
||||
|
||||
StringBuilder url = new StringBuilder(wechatOfficialAccountProperties.getAuthorize().getAccessTokenUrl());
|
||||
url.append("?appid={appid}&secret={secret}&code={code}&grant_type={grant_type}");
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
WechatOfficialAccountAccessTokenForUser wechatOfficialAccountAccessTokenForUser = restTemplate.getForObject(url.toString(), WechatOfficialAccountAccessTokenForUser.class, params);
|
||||
String resultJson = restTemplate.getForObject(url.toString(), String.class, params);
|
||||
WechatOfficialAccountAccessTokenForUser wechatOfficialAccountAccessTokenForUser = new ObjectMapper().readValue(resultJson, WechatOfficialAccountAccessTokenForUser.class);
|
||||
if (wechatOfficialAccountAccessTokenForUser == null) {
|
||||
LOG.error("获取用户AccessToken异常");
|
||||
throw new WechatAccessTokenForUserException("获取用户AccessToken异常");
|
||||
@ -183,14 +188,15 @@ public class WechatOfficialAccountManager {
|
||||
* @param openid
|
||||
* @return
|
||||
*/
|
||||
public WechatOfficialAccountUserInfo getUserInfo(String accessToken, String openid) {
|
||||
public WechatOfficialAccountUserInfo getUserInfo(String accessToken, String openid) throws IOException {
|
||||
Map<String, Object> params = new HashMap<>(2);
|
||||
params.put("access_token", accessToken);
|
||||
params.put("openid", openid);
|
||||
StringBuilder url = new StringBuilder(wechatOfficialAccountProperties.getAuthorize().getUserinfoUrl());
|
||||
url.append("?access_token={access_token}&openid={openid}&lang=zh_CN");
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
WechatOfficialAccountUserInfo wechatOfficialAccountUserInfo = restTemplate.getForObject(url.toString(), WechatOfficialAccountUserInfo.class, params);
|
||||
String resultJson = restTemplate.getForObject(url.toString(), String.class, params);
|
||||
WechatOfficialAccountUserInfo wechatOfficialAccountUserInfo = new ObjectMapper().readValue(resultJson, WechatOfficialAccountUserInfo.class);
|
||||
if (wechatOfficialAccountUserInfo == null) {
|
||||
throw new WechatUserInfoException("获取微信用户信息失败");
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ public class WechatOfficialAccountUserInfo {
|
||||
private String country;
|
||||
private String headimgurl;
|
||||
private String[] privilege;
|
||||
private String language;
|
||||
private String unionid;
|
||||
private Integer errcode;
|
||||
private String errmsg;
|
||||
@ -91,6 +92,14 @@ public class WechatOfficialAccountUserInfo {
|
||||
this.privilege = privilege;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language == null ? "" : language.trim();
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public String getUnionid() {
|
||||
return unionid == null ? "" : unionid.trim();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user