##原理: 前端生成二维码,存储随机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;
}
}
}