1、已认证的公众号(必须为服务号,订阅号没有该接口的权限)
2、一个网址,用于微信回调,推荐一个内网穿透的工具:内网穿透
3、Redis,用于存储token
4、一个SpringBoot项目
二、实现原理1、使用微信公众号(服务号)的appId和appSecret生成一个token,这个token可以复用,但是有时效性
2、使用token当做参数调用微信api:qrcode/create创建一个二维码
3、使用微信扫码,用户订阅后,微信官方会回调我们的一个地址,将openId传过来
4、将openId保存下来,下次扫描时根据openId进行判断用户身份
三、注意点1、只有服务号才有生成带参数的二维码接口权限
2、该接口每天100000次,适用于小规模用户登录
3、获取的AccessToken有时效性,可以利用redis进行保存
4、公众号开发有白名单限制,所以服务端在调用时需要配置白名单
四、实现步骤 公众号相关 1、登录公众号,获取appId和appKey 2、配置服务器回调地址 服务端相关 1、创建SpringBoot项目将复制下来的appId和appkey配置好,并加上一个redis 2、由于微信的回调值格式是XML格式,所以需要一个解析工具类package com.zzj.qlogin.utils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class XmlUtil {
public static Map parseXML(InputStream in){
Map map=new HashMap<>();
try {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(in);
Element root = document.getRootElement();
Iterator iterator = root.elementIterator();
while (iterator.hasNext()){
Element element = (Element) iterator.next();
map.put(element.getName(),element.getStringValue());
}
} catch (DocumentException e) {
e.printStackTrace();
}
return map;
}
}
3、回调接口,此处需要区分两个不同的事件:订阅和扫码,简单的处理逻辑如下
@PostMapping("/handleWxCheckSignature")
@ResponseBody
public String handleWxEvent(HttpServletRequest request){
try {
InputStream inputStream = request.getInputStream();
Map map = XmlUtil.parseXML(inputStream);
String userOpenId = (String) map.get("FromUserName");
String event = (String) map.get("Event");
if("subscribe".equals(event)){
// TODO:获取openid判断用户是否存在,不存在则获取新增用户,自己的业务
//自己生成的二维码不管是关注还是扫码都能取到ticket凭证
String ticket = (String) map.get("Ticket");
redisCacheManager.set(ticket,ticket,10*60);
logger.info("用户关注:{}",userOpenId);
}else if("SCAN".equals(event)){
//自己生成的二维码不管是关注还是扫码都能取到ticket凭证
String ticket = (String) map.get("Ticket");
redisCacheManager.set(ticket,ticket,10*60);
logger.info("用户扫码:{}",userOpenId);
}
logger.info("接收参数:{}",map);
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}



