扫码登陆后端部分

Posted by zjh on December 5, 2021

##原理: 前端生成二维码,存储随机ID,并注册到websocket的服务端,手机扫码后,带上token访问校验端,并且授权给核心工厂,确认登陆后,发送登录成功的信息和授权以后的token给前端,前端做token存储和页面跳转

附件:

文件名|地址 :–:|:–: 后端压缩包|scanLogin.zip 前端demo页面|websocket.html


核心代码展示

1、websocket配置(启动器)

@SpringBootApplication
@EnableWebSocket
public class LoginDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(LoginDemoApplication.class, args);
    }
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2、websocket服务端


import com.saoma.logindemo.factory.CodeFactory;
import org.springframework.stereotype.Component;

import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Classname WebSocketDemo
 * @Description
 * @Date 2021/2/209:52
 * @Author zjhchester
 */
@ServerEndpoint("/scanlogin/{code}")
@Component
public class WebSocketServer {
    private static Map<String, WebSocketServer> clients = new ConcurrentHashMap();
    private Session session;
    private String code;
    private static Integer threadStatus = 0;
    public WebSocketServer() {

    }
    private CodeFactory codeFactory = SpringUtil.getBean(CodeFactory.class);
    @OnOpen
    public void onOpen(@PathParam("code") String code, Session session) throws IOException {
        this.code = code;
        this.session = session;
        clients.put(code, this);

        System.out.println(code);
        codeFactory.setCode(code,session.toString());
        sendMessageTo("connect success!",code);
    }
    public void sendMessageTo(String message, String to) throws IOException {
        Iterator var3 = clients.values().iterator();
        while(var3.hasNext()) {
            WebSocketServer item = (WebSocketServer)var3.next();
            if (item.code.equals(to)) {
                item.session.getAsyncRemote().sendText(message);
            }
        }
    }
}

3、核心工厂

import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @Classname CodeFacotory
 * @Description 扫码登录核心工厂
 * @Date 2021/2/209:56
 * @Author zjhchester
 */
@Component
public  class CodeFactory {
    /**
     * key: 生成的随机码
     * value: 绑定的socket  sessionID
     */
    private static ConcurrentHashMap<String,String> codeFactory;
    static {
        codeFactory = new ConcurrentHashMap<>(1);
    }
    public String getCode(String code){
        return codeFactory.get(code);
    }
    public String setCode(String code,String session){
        return codeFactory.put(code,session);
    }
}

4、校验controller

import com.saoma.logindemo.conf.SpringUtil;
import com.saoma.logindemo.conf.WebSocketServer;
import com.saoma.logindemo.factory.CodeFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Objects;
import java.util.UUID;

/**
 * @Classname scanDemo
 * @Description
 * @Date 2021/2/209:50
 * @Author zjhchester
 */
@RestController
public class ScanDemoController {
    private final static String TRUE= "true";
    private final CodeFactory codeFactory;
    private final WebSocketServer webSocketServer;
    public ScanDemoController(CodeFactory codeFactory, WebSocketServer webSocketServer) {
        this.codeFactory = codeFactory;
        this.webSocketServer = webSocketServer;
    }

    /**
     * 校验登陆
     * @return result
     */
    @GetMapping("/codeverify")
    public String codeCreate(String code) throws IOException {
        String session = codeFactory.getCode(code);
        if(Objects.nonNull(session)){
            System.out.println(session);
            codeFactory.setCode(code,"true");
            webSocketServer.sendMessageTo("已在手机上扫描,请确认登录",code);
        }
        return code;
    }


    @GetMapping("/confirmlogin")
    public Boolean confirmLogin(String code) throws IOException {
        String verifyResult = codeFactory.getCode(code);
        if(TRUE.equals(verifyResult)){
            SpringUtil.getBean(WebSocketServer.class).sendMessageTo("登录成功",code);
            return true;
        }else{
            return false;
        }
    }
}