微信开放平台第三方授权(第二篇)-wechat授权配置

微信开放平台第三方授权(第二篇)-wechat授权配置_第1张图片

1.授权步骤开发

微信开放平台第三方授权(第二篇)-wechat授权配置_第2张图片

参考牛人的文档,按照步骤集成。

  1. 配置微信第三方平台中的授权事件接收URL:http://my-domain/notify/receive_ticket
  2. 配置微信第三方平台中的公众号消息与事件接收URL http://my-domain/notify/APPID/callback
  3. 首次启动后需要 等待收到 微信推送的 component_verify_ticket 后才可以使用接口 (在第三方平台创建审核通过后,微信服务器每隔10分钟会向第三方的消息接收地址推送一次component_verify_ticket,用于获取第三方平台接口调用凭据)
  4. 浏览器访问:http://my-domain/api/auth/goto_auth_url_show 点击 go 跳转到微信授权页面 扫码授权

 2.开发步骤

增加weixin-java-open依赖,老项目用的是3.3.0版本,建议用4.0以上的版本。


    com.github.binarywang
    weixin-java-open
    3.3.0
  • 授权获取component_verify_ticket方式
package com.test.wechat.controller;

import com.test.wechat.consts.WechatOpenConst;
import com.test.wechat.service.WechatOpenService;
import com.test.wechat.util.ServletUtil;
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.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

/**
 * @author 007
 */
@RestController
@RequestMapping("/wechatOpen/platform")
public class WechatOpenNotifyController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    protected WechatOpenService wxOpenService;

    @Autowired
    private ValueOperations valOps;
    @Autowired
    RedisTemplate redisTemplate;

    @RequestMapping("/receive_ticket")
    public Object receiveTicket(String key,@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) throws WxErrorException {
        logger.info(
                "\n接收微信请求:[key=[{}],[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                key,signature, encType, msgSignature, timestamp, nonce, requestBody);

        ServletUtil.setKey(key);
        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);
        logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
        String componentVerifyTicket=inMessage.getComponentVerifyTicket();
        if(redisTemplate.getExpire(WechatOpenConst.OPEN_PLATFORM_TICKET + key)<10*60) {
            valOps.set(WechatOpenConst.OPEN_PLATFORM_TICKET + key, componentVerifyTicket, 60 * 60 * 12, TimeUnit.SECONDS);
        }
        wxOpenService.getComponentAccessToken(key, componentVerifyTicket);
        try {
            String out = wxOpenService.getWxOpenComponentService().route(inMessage);
            logger.debug("\n组装回复信息:{}", out);
        } catch (WxErrorException e) {
            logger.error("receive_ticket", e);
        }
        return "success";
    }



    @RequestMapping("{appId}/callback")
    public Object callback(String key,@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) {
        logger.info(
                "\n接收微信请求:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
        ServletUtil.setKey(key);
        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);
        logger.info("\n消息解密后内容为:\n{} ", inMessage.toString());
        // 全网发布测试用例
        if (StringUtils.equalsAnyIgnoreCase(appId, "wx6c317d44449bfd92", "wx570bc396a51b8ff8")) {
            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.route(inMessage);
            if(outMessage != null){
                out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, wxOpenService.getWxOpenConfigStorage());
            }
        }
        return out;
    }
}
  • 编写授权代码-授权地址
package com.test.wechat.controller;

import com.test.wechat.service.WechatOpenService;
import com.test.wechat.util.ServletUtil;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 007
 */
@Controller
@RequestMapping("/wechatOpen/open/api")
public class WechatOpenApiController {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private WechatOpenService wxOpenService;
    @Autowired
    private ValueOperations valOps;

    @GetMapping("/auth/goto_auth_url_show")
    @ResponseBody
    public String gotoPreAuthUrlShow(String key) {
        String hrefUrl="go";
        return hrefUrl;
    }

    @GetMapping("/auth/goto_auth_url")
    public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response) {
        String key = request.getParameter("key");
        ServletUtil.setKey(key);
        String host = request.getHeader("host");
        String url = "https://" + host + "/wechatOpen/open/api/auth/jump?key=" + key;
        try {
            url = wxOpenService.getWxOpenComponentService().getPreAuthUrl(url);
            // 添加来源,解决302跳转来源丢失的问题
            response.addHeader("Referer", "https://" + host);
            response.sendRedirect(url);
        } catch (WxErrorException | IOException e) {
            logger.error("gotoPreAuthUrl", e);
            throw new RuntimeException(e);
        }
    }

    @GetMapping("/auth/jump")
    @ResponseBody
    public WxOpenQueryAuthResult jump(String key, @RequestParam("auth_code") String authorizationCode) {
        try {
            ServletUtil.setKey(key);
            WxOpenQueryAuthResult queryAuthResult = wxOpenService.getWxOpenComponentService().getQueryAuth(authorizationCode);
            logger.info("getQueryAuth", queryAuthResult);
            //存储授权appId,和authorCode
            valOps.set("wxOpen:" + queryAuthResult.getAuthorizationInfo().getAuthorizerAppid(), authorizationCode);
            wxOpenService.updateAuthAccount(key,authorizationCode);
            return queryAuthResult;
        } catch (WxErrorException e) {
            logger.error("gotoPreAuthUrl", e);
            throw new RuntimeException(e);
        }
    }

    @GetMapping("/get_authorizer_info")
    @ResponseBody
    public WxOpenAuthorizerInfoResult getAuthorizerInfo(@RequestParam String appId) {
        try {
            return wxOpenService.getWxOpenComponentService().getAuthorizerInfo(appId);
        } catch (WxErrorException e) {
            logger.error("getAuthorizerInfo", e);
            throw new RuntimeException(e);
        }
    }
}
  •  这个用到的工具类
public class ServletUtil {
    private static final ThreadLocal tl = new ThreadLocal();

    public static String getKey() {
        //	ServletRequestAttributes	attributes=(ServletRequestAttributes)  RequestContextHolder.getRequestAttributes();
        //	return (String) attributes.getAttribute("key", RequestAttributes.SCOPE_REQUEST);//attributes.getRequest().getAttribute("key").toString();
        return tl.get();
    }


    public static void setKey(String key) {
        //	ServletRequestAttributes	attributes=(ServletRequestAttributes)  RequestContextHolder.getRequestAttributes();
        //	attributes.setAttribute("key",key, RequestAttributes.SCOPE_REQUEST);
        //	//attributes.getRequest().setAttribute("key",key);
        tl.set(key);
    }

 授权中获取ticket通过上面的receiveTicket这个方法

  • component_verify_ticket 的有效时间为12小时,比 component_access_token 更长,建议保存最近可用的component_verify_ticket,在 component_access_token 过期之前都可以直接使用该 component_verify_ticket 进行更新,避免出现因为 component_verify_ticket 接收失败而无法更新 component_access_token 的情况。其中component_access_token获取发送消息的token时需要用到,由于这个wx-java-open没有实现发消息功能,需要集成weixin-java-mp通用发消息功能。
  • weixin-java-mp依赖,通过这个就可以使用微信的通用发送消息接口,这里的access_token需要使用授权的auth_access_token来发送消息。


    com.github.binarywang
    weixin-java-mp
    3.3.0

微信公众平台接口

客服账号管理 | 微信开放文档

微信开放平台第三方授权(第二篇)-wechat授权配置_第3张图片

微信开放平台第三方授权(第二篇)-wechat授权配置_第4张图片

authorizer_access_token获取方式 ,这个比较复杂,需要五步,其中component_access_token,authorizer_access_token有效期都有两小时。

Token生成说明 | 微信开放文档

微信开放平台第三方授权(第二篇)-wechat授权配置_第5张图片

其中authcode在授权后会拿到,需要保存下来。

 微信开放平台第三方授权(第二篇)-wechat授权配置_第6张图片

ps:下面继续讲解下一步代码 

你可能感兴趣的:(wechat,微信开放平台)