企业微信对接 代理 WXJava Ngnix映射 weixin-java-cp
<!--企业微信SDK--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-cp</artifactId><version>4.7.0</version></dependency>
我自己实现方法为了打印企业微信解密消息,可以使用WXJava 原生的方法,我是ngnix代理。
导入WXJava示例项目的包
package net.healthan.digital.wxcp.controller.single;import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.XmlUtils;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.WxCpUserDetail;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
import net.healthan.digital.common.core.exception.BizErrorException;
import net.healthan.digital.common.core.util.R;
import net.healthan.digital.common.security.annotation.Inner;
import net.healthan.digital.wxcp.config.single.WxCpConfiguration;
import net.healthan.digital.wxcp.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.List;import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.GET_USER_AUTH_INFO;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.USER_GET;/*** @author <a href="https://github.com/binarywang">Binary Wang</a>*/
@RestController
@RequestMapping("/wx/cp/portal/{agentId}")
@Slf4j
public class WxPortalController {private static final String PROXY_URL = "http://127.0.0.1:22380/wxcp-api";/*** 授权码登录*/@GetMapping("/login")@Inner(value = false)public R<HashMap<String, Object>> getCode(@PathVariable Integer agentId, String code) throws WxErrorException {log.info("wxcp-login-start");if (StringUtils.isBlank(code)) {throw new BizErrorException("code不能为空");}log.info("code=>{}", code);final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);if (ObjectUtil.isEmpty(wxCpService)) {throw new BizErrorException("请配置企业微信");}String getUserAuthInfoUrl = PROXY_URL + String.format(GET_USER_AUTH_INFO, code);String getUserAuthInfoResponse = wxCpService.get(getUserAuthInfoUrl, null);JSONObject getUserAuthInfoJsonObject = JSONObject.parseObject(getUserAuthInfoResponse);log.info("getUserAuthInfoUrl通过前置机发起企业微信请求=>{}", getUserAuthInfoResponse);
// String userTicket = getUserAuthInfoJsonObject.getString("userTicket");String userId = getUserAuthInfoJsonObject.getString("userid");HashMap<String, Object> hashMap = new HashMap<>();if (StringUtils.isBlank(userId)) {throw new BizErrorException("用户ID不能为空");}try {//读取通讯录信息String userGetUrl = PROXY_URL + USER_GET + userId;String userGetUrlResponse = wxCpService.get(userGetUrl, null);log.info("userGetUrl通过前置机发起企业微信请求=>{}", userGetUrlResponse);WxCpUser wxCpUser = WxCpGsonBuilder.create().fromJson(userGetUrlResponse, WxCpUser.class);List<WxCpUser.Attr> extAttrs = wxCpUser.getExtAttrs();if (CollectionUtil.isEmpty(extAttrs)) {throw new BizErrorException("第三方接口:企业微信-调用读取通讯录接口-获取工号失败");}boolean notHasWorkNo = true;for (WxCpUser.Attr extAttr : extAttrs) {if (StringUtils.equals(extAttr.getName(), "工号")) {if (StringUtils.isNotBlank(extAttr.getTextValue())) {notHasWorkNo = false;}}}if (notHasWorkNo) {throw new BizErrorException("第三方接口:企业微信-调用读取通讯录接口-获取工号失败");}hashMap.put("wxCpUser", wxCpUser);} catch (Exception e) {log.info(e.getMessage());throw new BizErrorException("第三方接口:企业微信-调用读取通讯录接口失败");}
// if (StringUtils.isNotBlank(userTicket)) {
// try {
// WxCpOAuth2Service oauth2Service = wxCpService.getOauth2Service();
// //获取用户敏感信息,未使用
// WxCpUserDetail userDetail = oauth2Service.getUserDetail(userTicket);
// hashMap.put("userDetail", userDetail);
// }catch (Exception e){
// e.printStackTrace();
// }
// }log.info("企业微信登录结果=>{}", JSON.toJSONString(hashMap));return R.ok(hashMap);}public void getS() {
// https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE}@Inner(value = false)@GetMapping(produces = "text/plain;charset=utf-8")public String authGet(@PathVariable Integer agentId,@RequestParam(name = "msg_signature", required = false) String signature,@RequestParam(name = "timestamp", required = false) String timestamp,@RequestParam(name = "nonce", required = false) String nonce,@RequestParam(name = "echostr", required = false) String echostr) {log.info("\nGet请求");log.info("\n接收到来自微信服务器的认证消息:signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]",signature, timestamp, nonce, echostr);if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {throw new IllegalArgumentException("请求参数非法,请核实!");}log.info("agentId=>{}", agentId);final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);if (wxCpService == null) {throw new IllegalArgumentException(String.format("未找到对应agentId=[%d]的配置,请核实!", agentId));}if (wxCpService.checkSignature(signature, timestamp, nonce, echostr)) {return new WxCpCryptUtil(wxCpService.getWxCpConfigStorage()).decrypt(echostr);}return "非法请求";}@Inner(value = false)@PostMapping(produces = "application/xml; charset=UTF-8")public String post(@PathVariable Integer agentId,@RequestBody String requestBody,@RequestParam("msg_signature") String signature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce) {log.info(String.valueOf(LocalDateTimeUtil.now()));log.info("\nPost请求");log.info("\n接收微信请求:[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",signature, timestamp, nonce, requestBody);log.info("agentId=>{}", agentId);final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);log.info("wxCpService=>{}", wxCpService);try {WxCpXmlMessage inMessage = fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),timestamp, nonce, signature);log.debug("\n消息解密后内容为:\n{} ", JsonUtils.toJson(inMessage));} catch (Exception e) {log.info("post微信请求解密失败" + e.getMessage());}// WxCpXmlOutMessage outMessage = this.route(agentId, inMessage);
// if (outMessage == null) {
// return "success";
// }// String out = outMessage.toEncryptedXml(wxCpService.getWxCpConfigStorage());
// log.debug("\n组装回复信息:{}", out);return "success";}public static WxCpXmlMessage fromEncryptedXml(String encryptedXml, WxCpConfigStorage wxCpConfigStorage,String timestamp, String nonce, String msgSignature) {log.info("fromEncryptedXml");WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage);log.info("cryptUtil:{}", cryptUtil);WxCpXmlMessage wxCpXmlMessage = fromXml(encryptedXml);String plainText = cryptUtil.decryptXml(msgSignature, timestamp, nonce, encryptedXml);log.info("解密后的原始xml消息内容:{}", plainText);if (StringUtils.isNotEmpty(wxCpXmlMessage.getAgentId())) {return fromXml(plainText, wxCpXmlMessage.getAgentId());} else {return fromXml(plainText);}}/*** From xml wx cp xml message.** @param xml the xml* @param agentId the agent id* @return the wx cp xml message*/public static WxCpXmlMessage fromXml(String xml, String agentId) {//修改微信变态的消息内容格式,方便解析xml = xml.replace("</PicList><PicList>", "");final WxCpXmlMessage xmlMessage = fromXml(xml);xmlMessage.setAgentId(agentId);return xmlMessage;}protected static WxCpXmlMessage fromXml(String xml) {//修改微信变态的消息内容格式,方便解析xml = xml.replace("</PicList><PicList>", "");final WxCpXmlMessage xmlMessage = XStreamTransformer.fromXml(WxCpXmlMessage.class, xml);xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml));return xmlMessage;}}
# 通用匹配所有以 /wxcp-api/ 开头的路径location ^~ /wxcp-api/ {# 移除请求路径中的 /wxcp-api 前缀rewrite ^/wxcp-api/(.*) /$1 break;# 转发到企业微信APIproxy_pass https://qyapi.weixin.qq.com;# 伪造客户端IP地址proxy_set_header X-Real-IP 127.0.0.1;proxy_set_header X-Forwarded-For 127.0.0.1;}