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;

@Configuration
public 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,其他信息都获取不到,但是一般我们登录流程的话是需要用户的昵称,头像,通过用户的授权,我们就可以直接获取到了,不用用户再次设置,这里用户的手机号也是不能获取到的。

  1. 用户扫码(只能或者一个带有参数的url,要转化成二维码,这里没有用前端了直接用草料二维码进行转换),如果用户扫码了以后没有关注公众号,那么当用户点击关注以后才会推送扫码关注事件,如果用户已经关注了那么手机会直接定位到会话页面
    • 用测试生成url
    @SpringBootTest
    

class WxLoginApplicationTests {
@Autowired
private WxMpService wxService;
@Test
void contextLoads() throws WxErrorException {
System.out.println(wxService.getQrcodeService().qrCodeCreateTmpTicket(“user_info”, 30000).getUrl());
}

}
```
- 生成二维码
在这里插入图片描述

  1. 接受微信推送的事件

  2. 返回给用户信息,消息的响应
    在这里插入图片描述

  3. 用户点击链接进行授权

  4. 用户打开地址,让后端获得权限,这里如果是域名备案了,那么会直接访问,否则要自己到浏览器打开网址才行。

  5. 此时获取到了用户的信息,已经成功进行了关联啦!–>即能够获得用户的昵称,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+"\'>登录</a>")
                    .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();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xwhking

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值