企业微信对接 代理 WXJava Ngnix映射 weixin-java-cp

发布于:2025-09-01 ⋅ 阅读:(21) ⋅ 点赞:(0)
        <!--企业微信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;
        # 转发到企业微信API
        proxy_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;
    }