微信公众号登录网站
需求:微信公众号登录网站,获取用户信息
前提条件
- 微信公众号已经认证
- 拥有服务器,可以接收微信服务器的回调
步骤
1、获取微信公众号的appid和appsecret
2、接入服务器,接收微信服务器的回调,需要有域名,可以使用内网穿透工具,例如cpolar
首先需要准备好图中的资源
说明:
URL表示微信验证服务端是否存在,需要按照要求进行配置,例如我这里的地址是
https://13a34511.r1.cpolar.top/api/user/wxcheck
所以必须在自己的服务上准备好响应的接口
//外层还有/user @GetMapping("wxcheck") public String wxCheck(@RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam("echostr") String echostr) { if (userService.wxCheck(signature, timestamp, nonce, wxOpenConfig.getToken())) { return echostr; } else { return "error"; } }
需要按照微信的要求返回数据,要求如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
@Override public Boolean wxCheck(String signature, String timestamp, String nonce, String token) { // 微信公众号接入校验 // 将token、timestamp、nonce三个参数进行字典序排序 String[] arr = new String[]{token, timestamp, nonce}; Arrays.sort(arr); // 将三个参数字符串拼接成一个字符串进行sha1加密 StringBuilder content = new StringBuilder(); for (String s : arr) { content.append(s); } String tmpStr = MYDigestUtils.sha1DigestAsHex(content.toString()); log.info("微信公众号接入校验,signature = {}, tmpStr = {}", signature, tmpStr); return signature.equals(tmpStr); }
接着提交上面的表单后会提示验证通过
3、接下来就是获取access_token了
java@Override public String getAccessToken() { // 获取access_token String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", wxOpenConfig.getAppId(), wxOpenConfig.getAppSecret()); // 发送请求 String result = restTemplate.getForObject(url, String.class); log.info("获取access_token,result = {}", result); return result; } ```
4、生成带 Ticket 二维码
@Override
public String getQRCode(String accessToken) {
// 获取二维码
String url = String.format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s", accessToken);
// 5分钟过期
String body = WXUtils.getQRCodeBody("300", "QR_STR_SCENE");
String result = restTemplate.postForObject(url, body, String.class);
log.info("获取二维码,result = {}", result);
return result;
}
5、将二维码的ticket返回给前端,前端请求到二维码图片展示给用户
6、用户扫码后会将响应的事件推送给上面的URL,只是将GET请求转换位POST请求,格式为:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
<EventKey><![CDATA[qrscene_123123]]></EventKey>
<Ticket><![CDATA[TICKET]]></Ticket>
</xml>
当然有很多事件类型,我们可以定义策略模式分别处理
@Slf4j
public class DispatchEventHandle {
private final Map<String, EventHandle> eventHandleMap = new HashMap<>();
{
eventHandleMap.put("subscribe", new SubscribeEventHandle());
eventHandleMap.put("SCAN", new ScanEventHandle());
}
public void dispatch(JSONObject jsonObject) {
String eventType = jsonObject.getJSONObject("xml").getStr(WxEventHandleConstants.EVENT_TYPE_KEY);
log.info("事件类型:{}", eventType);
EventHandle eventHandle = eventHandleMap.get(eventType);
if (eventHandle == null) {
log.error("未找到对应的事件处理器");
return;
}
eventHandle.handle(jsonObject);
}
}
接收请求的接口定义为
@PostMapping("wxcheck")
public String event(@RequestBody String xml) {
String msgType = WXUtils.getMsgType(xml);
if ("event".equals(msgType)) {
DispatchEventHandle dispatchEventHandle = new DispatchEventHandle();
dispatchEventHandle.dispatch(JSONUtil.xmlToJson(xml));
}
return xml;
}