实现微信公众号扫码登录全过程(最详细)
发表于更新于
阅读量: 深圳
TOC(真心顶不住微信公众号开发文档的乱并且刚接触的开发者绝对一头雾水,决心编写,防止更多人跳坑!)
前期准备
注册并配置微信公众号,获取 AppID 和 AppSecret。
配置开发者模式,设置服务器 URL 和 Token。(这一步以下会细讲)
认证的公众号
认证的公众号一年年费 300RMB,可以拥有“生成带参数的二维码”这一项接口权限,以及支付借口权限等具体可以去官方文档登录后查看 “设置与开发”-》“接口权限”
配置准备
在 springboot 中 application.yml 配置微信公众号配置,appid、secret、token、aesKey,以及回调的接口 callback
1 2 3 4 5 6 7 8
| wx: mp: callback: configs: - appId: secret: token: aesKey:
|
在 pom.xml 添加微信公众号开发的架包(或者自己写也可省了略)
1 2 3 4
| <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> </dependency>
|
初始化 WxMpService
在配置类中初始化 WxMpService 类的方法返回 server 注入 Bean 中,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Bean public WxMpService wxMpService() { final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs(); if (configs == null) { throw new RuntimeException("没有配置微信公众号信息!"); }
WxMpService service = new WxMpServiceImpl(); service.setMultiConfigStorages(configs .stream().map(a -> { WxMpDefaultConfigImpl configStorage; configStorage = new WxMpDefaultConfigImpl(); configStorage.setAppId(a.getAppId()); configStorage.setSecret(a.getSecret()); configStorage.setToken(a.getToken()); configStorage.setAesKey(a.getAesKey()); return configStorage; }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o))); return service; }
|
核心代码
可以使用 Cpolar Web UI 来做内网穿透进行测试,具体安装和设置可以在本站搜索“Cpolar 内网穿透”,没有的只能发布自己服务器进行 url 配置
- 首先先在微信公众号填写服务器配置
服务器地址(URL)一定要外网能访问,并且验证签名后返回 echostr,服务器配置的 token 和公众号的 token 要一致,这样才能在公众号上配置成功
验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@GetMapping(value = "/authGet", produces = "text/plain;charset=utf-8") public String authGet(@RequestParam(name = "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) { if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { throw new IllegalArgumentException("请求参数非法,请核实!"); }
if (wxService.checkSignature(timestamp, nonce, signature)) { return echostr; }
return "非法请求"; }
|
- 生成和请求一张带参数的二维码,返回给前端扫码
1 2
| WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) EXPIRE_TIME.getSeconds());
|
- 扫码后,微信回调服务器接口;
有两种情况 1.如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。 2.如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。
post 的方式推送事件:1、事件推送将会推送给公众号在公众平台官网开发者中心设置的服务地址中 2、如果公众号已将账号管理权限集(因为该接口权限从属于账号管理权限集)授权给第三方平台,那么将由第三方平台代公众号接收事件推送,具体是推送到第三方平台的公众号消息与事件接收 URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| String openid = wxMpXmlMessage.getFromUser(); Integer loginCode = Integer.parseInt(getEventKey(wxMpXmlMessage)); User user = userDao.getUserByOpenId(openid); if (Objects.nonNull(user) && StringUtils.isNotEmpty(user.getAvatar())) { ...返回前端更新登录状态等逻辑操作 return; }
if (Objects.isNull(user)) { ...先根据openid进行用户注册,即可 } RedisUtils.set(RedisKey.getKey(RedisKey.OPEN_ID_STRING, openid), loginCode, 60, TimeUnit.MINUTES); ...{返回前端逻辑}
String skipUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack")); WxMpXmlOutMessage.TEXT().build(); return new TextBuilder().build("请点击链接授权:<a href=\"" + skipUrl + "\">登录</a>", wxMpXmlMessage, wxMpService);
|
回调接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| String openid = wxMpXmlMessage.getFromUser(); Integer loginCode = Integer.parseInt(getEventKey(wxMpXmlMessage)); User user = userDao.getUserByOpenId(openid); if (Objects.nonNull(user) && StringUtils.isNotEmpty(user.getAvatar())) { ...返回前端更新登录状态等逻辑操作 return; }
if (Objects.isNull(user)) { ...先根据openid进行用户注册,即可 } RedisUtils.set(RedisKey.getKey(RedisKey.OPEN_ID_STRING, openid), loginCode, 60, TimeUnit.MINUTES); ...{返回前端逻辑}
String skipUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack")); WxMpXmlOutMessage.TEXT().build(); return new TextBuilder().build("请点击链接授权:<a href=\"" + skipUrl + "\">登录</a>", wxMpXmlMessage, wxMpService);
|
未认证公众号
未认证的公众号的步骤基本差不多,差别就是没有生成带参数的二维码的权限,通过“接收普通消息”和“接收事件推送”这两个接口权限去验证 openid 用户。主要两种方式:1.前端提供参数扫码关注公众号后回复参数校验通过。2.关注公众号后开发者推送参数校验,在前端填写后登录。实现方式基本一致,就不分开讲述。这里主要讲前端提供参数扫码关注公众号后回复参数校验通过。
前端提供参数扫码关注公众号后回复参数校验通过
首先需要做的步骤和上述差不多
配置准备
在 springboot 中 application.yml 配置微信公众号配置,appid、secret、token、aesKey,以及回调的接口 callback
1 2 3 4 5 6 7 8
| wx: mp: callback: configs: - appId: secret: token: aesKey:
|
在 pom.xml 添加微信公众号开发的架包(或者自己写也可省了略)
1 2 3 4
| <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> </dependency>
|
初始化 WxMpService
在配置类中初始化 WxMpService 类的方法返回 server 注入 Bean 中,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Bean public WxMpService wxMpService() { final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs(); if (configs == null) { throw new RuntimeException("没有配置微信公众号信息!"); }
WxMpService service = new WxMpServiceImpl(); service.setMultiConfigStorages(configs .stream().map(a -> { WxMpDefaultConfigImpl configStorage; configStorage = new WxMpDefaultConfigImpl(); configStorage.setAppId(a.getAppId()); configStorage.setSecret(a.getSecret()); configStorage.setToken(a.getToken()); configStorage.setAesKey(a.getAesKey()); return configStorage; }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o))); return service; }
|
核心代码
可以使用 Cpolar Web UI 来做内网穿透进行测试,具体安装和设置可以在本站搜索“Cpolar 内网穿透”,没有的只能发布自己服务器进行 url 配置
- 首先先在微信公众号填写服务器配置
服务器地址(URL)一定要外网能访问,并且验证签名后返回 echostr,服务器配置的 token 和公众号的 token 要一致,这样才能在公众号上配置成功
验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@GetMapping(value = "/authGet", produces = "text/plain;charset=utf-8") public String authGet(@RequestParam(name = "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) { if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { throw new IllegalArgumentException("请求参数非法,请核实!"); }
if (wxService.checkSignature(timestamp, nonce, signature)) { return echostr; }
return "非法请求"; }
|
- 再写一个接口 authGet,请求方式为 Post
推送的请求包
1 2 3 4 5 6 7
| <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[FromUser]]></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[subscribe]]></Event> </xml>
|
用户关注/取消公众号。发送消息给公众号,都进这个方法,根据消息去处理登录逻辑即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @PostMapping(value = "/authGet", produces = "application/xml; charset=UTF-8") public String wxtoMessage(@RequestBody String xmlData) {
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(xmlData); if ("event".equals(inMessage.getMsgType()) && ("SCAN".equals(inMessage.getEvent()) || "subscribe".equals(inMessage.getEvent()))) { String openId = inMessage.getFromUserName(); String msgType = inMessage.getMsgType();
if(msgType为subscribe){ if(用户存在){
}else{ }
}else{
}
return "success"; }
return "success"; }
|