扫码登录的简单实现方式

扫码登录的简单实现方式

  •  9个月前
  •  514
  •  Java SpringBoot WebSocket 

需求

用公司的APP(非微信QQ)扫描网页的二维码进行登录。

流程

  1. 浏览器向服务器请求登录所需的二维码。
  2. 服务器返回二维码和一个唯一的标识,标识存储到redis并设置过期时间。
  3. 浏览器对二维码进行展示并根据服务器返回的标识创建WebSocket连接。
  4. 用户打开APP扫描二维码,请求二维码上携带的校验地址。注:扫码时APP需处于登录状态。
  5. 校验逻辑处理成功后通过WebSocket通知浏览器是否返回成功。
  6. 浏览器展示登录结果并处理对应逻辑。

根据流程,服务端需要提供三个服务:两个api接口和一个WebSocket Server。其中api用于初始化和扫码后的校验,WebSocket用于通知扫码登录的结果。

这里的WebSocket是可以使用Ajax轮询的方式替代的,但是轮询的方式会增加服务器的压力,实现起来也不够优雅,所以这里我们使用WebSocket。如果你之前没有使用过WebSocket,可以看我的这篇文章了解一下。

初始化接口

  • 生成二维码。
  • 生成唯一标识,与二维码绑定。存入redis并设置过期时间。该标识用户区分二维码和创建WebSocket连接。

// 方法签名:
@ResponseBody
@GetMapping("/init")
public Response generateQRCode() {}

// 返回结果:
{
    "code": 200,
    "message": "Success!",
    "date": 1568618978859,
    "data": {
        "qr": "base64格式的二维码",
        "ticket": "vJ65p2mBUZPtmQKtvGTdpTLfe3WiNWgt"    // 票据,创建websocket连接时需携带
    },
    "messages": "Success!"
}

扫码校验

  • 扫码校验时需要APP处于登录状态并携带初始化时服务器返回的唯一标识,服务器处理后会告诉APP是否登录结果。

// 方法签名:
@ResponseBody
@GetMapping("/validate")
public Response validateTicket(@RequestParam String ticket) {}

// 返回结果:
{
    "code": 200,
    "message": "Success!",
    "date": 1568618978859,
    "data": {},
    "messages": "Success!"
}

WebSocket Server

  • WebSocket用于通知浏览器登录结果,在浏览器创建连接时也需要携带唯一标识。

// 核心代码
@Controller
@ServerEndpoint(value = "/ws/qrcode/{ticket}")
public class ScanQRCodeServer {

    private static ConcurrentHashMap<String, Session> sockets = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("ticket") String ticket) {
        System.out.println("socket open .");
        System.out.println("ticket:" + ticket);
        sockets.put(ticket, session);
        System.out.println("size:" + sockets.size());
    }

    @OnClose
    public void onClose(@PathParam("ticket") String ticket) {
        System.out.println("close:" + ticket);
        System.out.println("socket close .");
        sockets.remove(ticket);
        System.out.println("size:" + sockets.size());
    }

    public void response(String ticket, String message) throws IOException {
        System.out.println("response : ticket:" + ticket + ", message:" + message);
        sockets.get(ticket).getBasicRemote().sendText(message);
    }

}

客户端

请求初始化接口,根据返回的信息展示二维码并创建WebSocket连接,等待服务器通知扫码结果。

// 核心代码
$.ajax({
    type: 'get',
    url: '/qrcode/init',
    dataType: 'json',
    success: function (resp) {
        let ticket = resp.data.ticket;
        let qr = resp.data.qr;
        // 展示二维码
        $('#qr').attr('src', 'data:image/png;base64,' + qr)

        // 创建WebSocket连接
        if ('WebSocket' in window) {
            webSocket = new WebSocket("ws://localhost:9000/ws/qrcode/" + ticket);
        } else {
            console.log('webSocket not support')
        }

        // 扫码后服务器的通知信息
        webSocket.onmessage = function (event) {
            console.log(event.data);
        };
    }
});

源码地址

https://github.com/chenpeidong/qrcode-login

扫一扫分享到微信

已有 条评论
写评论