Java 实现微信扫码授权登录_java微信扫码登录
一直想实现一下微信的扫码登录,现在终于来实践了。
要想实现微信的扫码登录肯定是直接浏览微信的官方开发者文档,从中就可以获取一切的用法。
实现步骤
创建服务号的测试号
- 首先要创建一个测试号,用于微信接口的调试,创建测试号地址
创建好了之后是这样的:
其中的 URL 是需要自己填写的,这个是接收微信事件的回调地址,微信会给你推送事件,这个配置接口我们后面写,token 可以随便写,不过后端符合微信的验证就好了。
创建一个SpringBoot的项目
这里直接通过 IDEA 创建一个后端项目,然后引入,WxJava 的 SDK,方便进行微信的交互,当然也可以自己写和微信的交互,但是太繁杂了,别人都写好了,为什么还写呢???
- 引入 WxJava 管理公众号
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>4.7.6-20250704.154059</version> </dependency>
- 填写测试号的一些密钥
wx.mp.appId=wx805bf0797a5f2911 # 必填wx.mp.secret=72256cbeffd04ba3d592e133fe8f1f7a #必填 wx.mp.token=xwhking
- 配置使用的Bean
package com.xwhking.wxlogin.config;import me.chanjar.weixin.mp.api.WxMpMessageRouter;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class WxConfig { @Value(\"${wx.mp.appId}\") private String appId; @Value(\"${wx.mp.secret}\") private String secret; @Value(\"${wx.mp.token}\") private String token; @Bean public WxMpService wxMpService() { WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); config.setAppId(appId); config.setSecret(secret); config.setToken(token); WxMpService service = new WxMpServiceImpl(); service.setWxMpConfigStorage(config); return service; } @Bean public WxMpMessageRouter messageRouter(WxMpService wxMpService) { final WxMpMessageRouter router = new WxMpMessageRouter(wxMpService); // 这里可以添加各种消息处理器 return router; }}
- 编写接口,用于校验,在测试号页面,启动了后端,就可以让微信校验成功(前提要配置网络地址,需要内网穿透)
微信校验流程图,如下。
校验规格如下
@RestController@RequestMapping(\"/wx/callback\")public class WxController { @Autowired private WxMpService wxMpService; @GetMapping public String verify(String signature, String timestamp, String nonce, String echostr) throws WxErrorException { boolean b = wxMpService.checkSignature(timestamp, nonce, signature); //是否满足微信的校验条件 if(b) { return echostr; } return null; }}
内网穿透
这里我介绍 cpolar下载 ,简单直接能够免费使用 24h 的http和https的随机域名,当然能够永久,不过需要购买罢了。其他的内网穿透推荐ngrok
, ftp
等
进入网页后点击相应的机型进行下载就好了。
windows下载好后,直接点开web就好
首先要登录,在官网注册就好了,进入后是下面的样子
编辑一下自己网站端口就行了,然后到在线隧道查看地址
扫码登录流程介绍
背景知识,如果用户没有点击授权信息的话,从微信扫码只能够获得用户的 OpenId,其他信息都获取不到,但是一般我们登录流程的话是需要用户的昵称,头像,通过用户的授权,我们就可以直接获取到了,不用用户再次设置,这里用户的手机号也是不能获取到的。
- 用户扫码(只能或者一个带有参数的url,要转化成二维码,这里没有用前端了直接用草料二维码进行转换),如果用户扫码了以后没有关注公众号,那么当用户点击关注以后才会推送扫码关注事件,如果用户已经关注了那么手机会直接定位到会话页面
- 用测试生成url
@SpringBootTest
class WxLoginApplicationTests {
@Autowired
private WxMpService wxService;
@Test
void contextLoads() throws WxErrorException {
System.out.println(wxService.getQrcodeService().qrCodeCreateTmpTicket(“user_info”, 30000).getUrl());
}
}
```
- 生成二维码
-
接受微信推送的事件
-
返回给用户信息,消息的响应
-
用户点击链接进行授权
-
用户打开地址,让后端获得权限,这里如果是域名备案了,那么会直接访问,否则要自己到浏览器打开网址才行。
-
此时获取到了用户的信息,已经成功进行了关联啦!–>即能够获得用户的昵称,openid,头像地址,这些信息一般来说也够了。
获取到的信息
WxOAuth2UserInfo(openid=owO-dvkozjjzycXgtaCCgFbzxxxx, nickname=DIOIT, sex=0, city=, province=, country=, headImgUrl=https://thirdwx.qlogo.cn/mmopen/vi_32/GcAobrQM3uzlReTKGs7KtuPUibUrYXzt3hluJCXHr7DCMibYoB2viabQ2PsVPq8BfbsDwIozz1vpdAx4oib4gnTCdQ/132, unionId=null, privileges=[])
代码实现
package com.xwhking.wxlogin.controller;import me.chanjar.weixin.common.api.WxConsts;import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;import me.chanjar.weixin.common.error.WxErrorException;import me.chanjar.weixin.common.util.crypto.SHA1;import me.chanjar.weixin.mp.api.WxMpMessageRouter;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import me.chanjar.weixin.mp.bean.result.WxMpUser;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping(\"/wx/callback\")public class WxController { @Autowired private WxMpService wxMpService; @Autowired private WxMpMessageRouter wxMpMessageRouter; @GetMapping public String verify(String signature, String timestamp, String nonce, String echostr) throws WxErrorException { boolean b = wxMpService.checkSignature(timestamp, nonce, signature); //是否满足微信的校验条件 if(b) { return echostr; } return null; } @PostMapping(produces = \"application/xml; charset=UTF-8\") public String post( @RequestBody String requestBody, @RequestParam(\"signature\") String signature, @RequestParam(\"timestamp\") String timestamp, @RequestParam(\"nonce\") String nonce, @RequestParam(name = \"encrypt_type\", required = false) String encType, @RequestParam(name = \"msg_signature\", required = false) String msgSignature) throws WxErrorException { if (!wxMpService.checkSignature(timestamp, nonce, signature)) { throw new IllegalArgumentException(\"非法请求\"); } // 处理消息 WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); System.out.println(\"inMessage\"+inMessage); // 如果是二维码扫描事件 if (inMessage.getEvent().equals(WxConsts.EventType.SCAN) || inMessage.getEvent().equals(WxConsts.EventType.SUBSCRIBE)) { String redirectUri = \"https://519e7b4c.r9.cpolar.cn/wx/callback/auth-callback\"; // 你的回调地址 String scope = \"snsapi_userinfo\"; // 需要获取用户信息 String state = \"random_state_123\"; // 防CSRF攻击 // 构造授权URL String authUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectUri, scope, state); // 可以回复消息 String APPID = wxMpService.getWxMpConfigStorage().getAppId(); String SECRET = wxMpService.getWxMpConfigStorage().getSecret(); String accessToken = wxMpService.getAccessToken(); WxMpUser wxMpUser = wxMpService.getUserService().userInfo(inMessage.getFromUser()); System.out.println(wxMpUser); WxMpXmlOutMessage outMessage = WxMpXmlOutMessage.TEXT() .content(\"<a href=\\\'\"+authUrl+\"\\\'>登录\") .fromUser(inMessage.getToUser()) .toUser(inMessage.getFromUser()) .build(); return outMessage.toXml(); } // 其他消息交给路由器处理 WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); if (outMessage != null) { return outMessage.toXml(); } return \"\"; } @GetMapping(\"/auth-callback\") public String callback( @RequestParam(\"code\") String code, @RequestParam(value = \"state\", required = false) String state) { // 验证state防止CSRF攻击 try { // 1. 用code换取access_token WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code); // 2. 获取用户信息 WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(accessToken, null); System.out.println(userInfo); return \"success\"; } catch (WxErrorException e) { return \"授权失败: \" + e.getMessage(); } }}