微信公众号跳转第三方活动

第一步:填写服务器配置

登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。同时,开发者可选择消息加解密方式:明文模式、兼容模式和安全模式。模式的选择与服务器配置在提交后都会立即生效,请开发者谨慎填写及选择。加解密方式的默认状态为明文模式,选择兼容模式和安全模式需要提前配置好相关加解密代码,详情请参考消息体签名及加解密部分的文档 。

微信公众号跳转第三方活动_第1张图片


微信公众号跳转第三方活动_第2张图片

@RequestMapping(value = "signature", method = RequestMethod.GET)
public void signature(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException{
    String signature = request.getParameter("signature");
    String timestamp = request.getParameter("timestamp");
    String nonce = request.getParameter("nonce");
    String echostr = request.getParameter("echostr");

    PrintWriter out = response.getWriter();
    if((signature!=null&×tamp!=null&&nonce!=null)&&CheckUtil.checkSignature(signature,timestamp,nonce)){
        //如果校验成功,将得到的随机字符串原路返回
        out.print(echostr);
    }
}

public static boolean checkSignature(String signature,String timestamp,String nonce){
    String[] arr = new String[]{token,timestamp,nonce};
    //排序
    Arrays.sort(arr);
    //生成字符串
    StringBuffer content = new StringBuffer();
    for (int i =0;ilength;i++){
        content.append(arr[i]);
    }
    //sha1加密
    String temp = getSha1(content.toString());
    return temp.equals(signature);
}

如果校验成功将得到随机字符串原路返回,验证URL有效性成功后即接入生效,成为开发者,之后即可愉快的进行开发了。

进入正题

这次要做的功能是在用户点击自定义菜单后,跳转第三方活动页面,进入活动页面需要带上微信用户的id标识,这里我们使用的是微信的openId,简单的说下openId,一个微信号与一个公众号对应一个固定不变的openid。所以一个微信号在一个公众号下的openid是不变的,如果换了一个对应的公众号,那就是另一个openid了。且只有在微信自带浏览器中打开的项目才可获取到,那么第一步就是需要获取到用户的openId。

通过用户的点击跳转获取用户openid就必须在菜单中动态绑定用户的openid,或者在菜单的跳转URL中填写微信提供的链接,官方给了两个链接类型

一种是Scope为snsapi_base的链接

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

另一种是Scope为snsapi_userinfo的链接

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

这两种链接的区别如下

应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)


这里我使用第一种通过 Scope为snsapi_base的方式

点击菜单时微信不会主动将用户的openId发给你,而是通过回调机制,这里我们需要先在自定义菜单中填写自己的url,在填写的url中将用户重定向到snsapi_base的url中,然后再在snsapi_base中配置获取用户openid以及用户其他信息,最后跳转到一个页面

@GetMapping(value = "/redirect")
public void WxRedirect(HttpServletResponse response)throws Exception{
    String sUrl = serverUrl+"/WxRedirect/oauth";
    String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx048aa1a561400011&redirect_uri="+URLEncoder.encode(sUrl,"UTF-8")+"?response_type=code&scope=snsapi_base&state=1&connect_redirect=1#wechat_redirect";
    response.sendRedirect(url);
}
@RequestMapping(value = "/oauth", method = RequestMethod.GET)
public void weixinOAuth(HttpServletRequest request, HttpServletResponse response)throws Exception {
    //得到code
    String code = request.getParameter("code");
    String redirectUrl = service.getRedirectUrl(code);
    response.sendRedirect(redirectUrl);
}

微信公众号跳转第三方活动_第3张图片

在访问成功的情况下,后台/oauth 接口将会获得微信带来的code参数,然后通过code换取网页授权access_token

获取code后,请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
//获取access_token
String getTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code".replace("APPID", WXappId).replace("SECRET", WXsecret).replace("CODE", code);
String result = urlConnectionUtils.urlOpen(getTokenUrl);
JSONObject jsonObject = JSONObject.fromObject(result);
String openId = (String) jsonObject.get("openid");
String access_token = (String)jsonObject.get("access_token");

拿到openId和access_token后我们就能做很多事了,这里我们要做的是用openId拼接活动跳转URL,拼好后返回给微信一个重定向到活动页面的地址,第一次尝试报错了

微信公众号跳转第三方活动_第4张图片


出现了redirect_url域名与后台配置不一致,网上查了资料,问题出在给微信的回调地址未在后台配置,

微信公众号跳转第三方活动_第5张图片

微信公众号跳转第三方活动_第6张图片

这里配上你的/aouth 接口地址即可。


但是!!!

以上方法只针对于服务号的操作,而我需要操作的是订阅号,订阅号并不支持通过自定义菜单获取用户openid,所以以上方案多次尝试都没能成功,唯一的途径获取用户openId就是通过引导用户来与公众号交互。微信会在用户回复的内容中带上openId,那么只能修改我们的代码了

首先看看微信消息机制

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上,这里的url,就是之前我们配置的与微信服务器认证的url,只不过认证是用get请求,发送消息post请求,那么我们再写一个

@RequestMapping(value = "signature", method = RequestMethod.POST)
public void retrunMessage(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException{
    System.out.println("消息进来了");
    response.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");
    PrintWriter out = response.getWriter();
    try {
        Map,String> map = xmlToMapUtil.xmlToMap(request);
        String fromUserName = map.get("FromUserName");
        String toUserName = map.get("ToUserName");
        String msgType = map.get("MsgType");
        String content = map.get("Content");

        String message = null;
        if("text".equals(msgType)){
            TextMessage text = new TextMessage();
            text.setFromUserName(toUserName); //原来的信息发送者,将变成信息接受者
            text.setToUserName(fromUserName); //原理的接受者,变成发送者
            text.setMsgType("text"); //表示消息的类型是text类型
            text.setCreateTime(new Date().getTime());
            text.setContent("点击活动:" + "http://stage.vpclub.cn/vphonor/WxRedirect/userRedirect?fromUserName="+fromUserName);
            message = textMessageToXml.textMessageToXml(text); //装换成 xml 格式发送给微信解析

            System.out.println(message);
        }
        out.print(message);
    } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

微信消息是以xml格式进行的传递和接收,所以我们先要对其进行传参解析,工具类代码:

public class xmlToMapUtil {

    public static Map,String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {

        Map,String> map = new HashMap,String>();
        SAXReader reader = new SAXReader();

        InputStream ins = request.getInputStream();
        Document doc = reader.read(ins);

        //获取根节点
        Element root = doc.getRootElement();

        List list = root.elements();

        for(Element e : list){
            map.put(e.getName(), e.getText());
        }
        ins.close();

        return map;
    }

返回解析,工具类:

public static String textMessageToXml(TextMessage textMessage){
    XStream xstream = new XStream();
    xstream.alias("xml", textMessage.getClass());
    return xstream.toXML(textMessage);
}

pom依赖


    com.thoughtworks.xstream
    xstream
    1.4.9

然后看看效果

微信公众号跳转第三方活动_第7张图片


这里接收消息成功了,后台获取到了用户openId,然后拼接成了Url返回给用户,引导用户点击

微信公众号跳转第三方活动_第8张图片可以看到跳转到了我们未配置任何信息的活动页面,也就是说跳转成功了,这种方法的弊端就是交互不太友好,暴露了用户openId,后期还得优化

多说一句

微信公众号开发的服务器必须是外网可访问的服务器地址,所以在本地调试时遇到的阻碍还是挺大的,每次都需要发到生产才能看到代码效果,推荐使用外网穿透工具(网上很多,可自行百度),将本地ip地址映射到公网ip上,微信填写映射ip地址就好,等测试完成后再换成正式生产地址

你可能感兴趣的:(微信公众号跳转第三方活动)