微信开放平台服务集成

This commit is contained in:
ronger 2020-03-17 17:33:35 +08:00
parent 637c66135c
commit e28e219428
4 changed files with 294 additions and 0 deletions

View File

@ -0,0 +1,68 @@
package com.rymcu.vertical.wx.mp.controller;
import com.rymcu.vertical.util.ContextHolderUtils;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @author ronger
*/
@Controller
@RequestMapping("/wx/oauth/{appId}")
public class WxoAuthController {
@Resource
private WxMpService wxMpService;
@Value("${resource.domain}")
private String domain;
@GetMapping
public String wxAuth(@PathVariable String appId, @RequestParam(name = "redirectUrl") String redirectUrl) {
wxMpService.switchoverTo(appId);
if ("wxa49093339a5a822b".equals(appId)) {
domain = "http://oae.nat300.top/vertical";
} else {
domain += "/vertical-console";
}
StringBuilder accessTokenUrl = new StringBuilder(domain).append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(domain + redirectUrl));
String oauth2Url = wxMpService.oauth2buildAuthorizationUrl(accessTokenUrl.toString(), WxConsts.OAuth2Scope.SNSAPI_BASE, null);
return "redirect:" + oauth2Url;
}
@GetMapping("getAccessToken")
public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
wxMpService.switchoverTo(appId);
WxMpOAuth2AccessToken oAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
boolean valid = wxMpService.oauth2validateAccessToken(oAuth2AccessToken);
if (!valid) {
throw new Exception("无权限");
}
WxMpUser wxMpUser =wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
return "redirect:" + redirectUrl;
}
@GetMapping("validJs")
@ResponseBody
public WxJsapiSignature validJs(String url) throws WxErrorException {
return wxMpService.createJsapiSignature(url);
}
@GetMapping("t")
public String reOauth() {
return "wx/oauth";
}
}

View File

@ -0,0 +1,42 @@
package com.rymcu.vertical.wx.open.config;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author <a href="https://github.com/007gzs">007</a>
*/
@Getter
@Setter
@ConfigurationProperties(prefix = "wx.open")
public class WxOpenProperties {
/**
* 设置微信三方平台的appid
*/
private String componentAppId;
/**
* 设置微信三方平台的app secret
*/
private String componentSecret;
/**
* 设置微信三方平台的token
*/
private String componentToken;
/**
* 设置微信三方平台的EncodingAESKey
*/
private String componentAesKey;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}
}

View File

@ -0,0 +1,110 @@
package com.rymcu.vertical.wx.open.controller;
import com.rymcu.vertical.wx.open.handler.WxOpenServiceHandler;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author <a href="https://github.com/007gzs">007</a>
*/
@RestController
@RequestMapping("/notify")
public class WxOpenNotifyController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
protected WxOpenServiceHandler wxOpenService;
@RequestMapping("/receive_ticket")
public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
this.logger.info(
"\n接收微信请求[signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!StringUtils.equalsIgnoreCase("aes", encType)
|| !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
// aes加密的消息
WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为\n{} ", inMessage.toString());
try {
String out = wxOpenService.getWxOpenComponentService().route(inMessage);
this.logger.debug("\n组装回复信息{}", out);
} catch (WxErrorException e) {
this.logger.error("receive_ticket", e);
}
return "success";
}
@RequestMapping("{appId}/callback")
public Object callback(@RequestBody(required = false) String requestBody,
@PathVariable("appId") String appId,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam("encrypt_type") String encType,
@RequestParam("msg_signature") String msgSignature) {
this.logger.info(
"\n接收微信请求[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!StringUtils.equalsIgnoreCase("aes", encType)
|| !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = "";
// aes加密的消息
WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为\n{} ", inMessage.toString());
// 全网发布测试用例
if (StringUtils.equalsAnyIgnoreCase(appId)) {
try {
if (StringUtils.equals(inMessage.getMsgType(), "text")) {
if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build(),
wxOpenService.getWxOpenConfigStorage()
);
} else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
}
} else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
}
} catch (WxErrorException e) {
logger.error("callback", e);
}
}else{
WxMpXmlOutMessage outMessage = wxOpenService.getWxOpenMessageRouter().route(inMessage, appId);
if(outMessage != null){
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, wxOpenService.getWxOpenConfigStorage());
}
}
return out;
}
}

View File

@ -0,0 +1,74 @@
package com.rymcu.vertical.wx.open.handler;
import com.rymcu.vertical.core.service.props.DynProps4FilesService;
import com.rymcu.vertical.wx.open.config.WxOpenProperties;
import me.chanjar.weixin.open.api.impl.WxOpenInRedisConfigStorage;
import me.chanjar.weixin.open.api.impl.WxOpenMessageRouter;
import me.chanjar.weixin.open.api.impl.WxOpenServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author ronger
*/
@Service
public class WxOpenServiceHandler extends WxOpenServiceImpl {
private Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private WxOpenProperties wxOpenProperties;
@Resource
private WxOpenMessageRouter wxOpenMessageRouter;
@Resource
private DynProps4FilesService dynProps4Files;
@Resource
private Environment env;
private static JedisPool pool;
@PostConstruct
public void init() {
WxOpenInRedisConfigStorage inRedisConfigStorage = new WxOpenInRedisConfigStorage(getJedisPool());
inRedisConfigStorage.setComponentAppId(wxOpenProperties.getComponentAppId());
inRedisConfigStorage.setComponentAppSecret(wxOpenProperties.getComponentSecret());
inRedisConfigStorage.setComponentToken(wxOpenProperties.getComponentToken());
inRedisConfigStorage.setComponentAesKey(wxOpenProperties.getComponentAesKey());
setWxOpenConfigStorage(inRedisConfigStorage);
wxOpenMessageRouter = new WxOpenMessageRouter(this);
wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
return null;
}).next();
}
private JedisPool getJedisPool() {
if (pool == null) {
synchronized (WxOpenServiceHandler.class) {
if (pool == null) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(dynProps4Files.getInt("REDIS_MAX_IDLE", JedisPoolConfig.DEFAULT_MAX_IDLE));
config.setMaxTotal(dynProps4Files.getInt("REDIS_MAX_TOTAL", JedisPoolConfig.DEFAULT_MAX_TOTAL));
config.setMaxWaitMillis(dynProps4Files.getLong("REDIS_MAX_WAIT", JedisPoolConfig.DEFAULT_MAX_WAIT_MILLIS));
config.setTestOnBorrow(true);
pool = new JedisPool(config, env.getProperty("spring.redis.host"),
dynProps4Files.getInt("REDIS_PORT", 6379), dynProps4Files.getInt(
"REDIS_MAX_WAIT", 1000), dynProps4Files.getProperty("REDIS_PASSWORD", env.getProperty("spring.redis.password")));
}
}
}
return pool;
}
public WxOpenMessageRouter getWxOpenMessageRouter() {
return wxOpenMessageRouter;
}
}