如何实现简易的扫码登录
大家好,我是梦辛工作室的灵,话说又是好久没有更新了,但这绝对不是因为楼主懒=-=,真哒真哒,好吧,假期太长了主要,然后就越耍越皮了=-=,不扯了,那进入今天的正题,如何实现 扫码登录,我这边画好了一个 简易的原理图便于 大家更好的理解:
显示由客户端 产生一个 带有指向登录地址并含有唯一ID的二维码,并与服务端保持长连接,楼主这里 为了方便直接使用的 ws 协议,你也可以使用 tcp协议来实现,这样就在服务端有了一个 待登录的客户端长连接,然后 用户扫码时 会获取到 该id 并且连接服务端 向生成二维码的客服端 发送 扫扫码成功通知,然后生成二维码的客户端刷新UI,显示 扫码成功,用户在 手机扫码成功的界面 点击确认登录,或输入账号密码登录,传给服务器,服务器 通过读取数据库验证密码通过后,将用户相关信息 发送给 客户端,这样就完成 扫码登录了,还是挺简单的吧,下面直接来看代码:
首先是 客户端:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>扫码登录实现Demo</title>
<script type="text/javascript" src="qrcode.min.js"></script>
<script type="text/javascript">
window.onload = function(res){
if ("WebSocket" in window)
{
// 打开一个 web socket 随机注册一个id
var id = createId(10);
var ws = new WebSocket("ws://localhost:8080/websocket?openid=" + id );
ws.onopen = function()
{
// Web Socket 已连接上,使用 send() 方法发送数据
console.log("成功建立连接");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
console.log("接收到数据:" + received_msg);
try{
var jsonData = JSON.parse(received_msg);
if (jsonData.account && jsonData.password) {
alert("账号 " + jsonData.account + " 登录成功");
}
if(jsonData.scan){
document.getElementById("success_div").style.display = "flex";
}
}catch(e){
}
};
ws.onclose = function()
{
// 关闭 websocket
console.log("连接已关闭...");
};
draw("http://127.0.0.1:8080/login.html?id=" + id,"content");
}
else
{
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
function createId(len){
var baseStr = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" + (new Date()).getTime();
var randStr = "";
for(var i = 0; i < len; i++){
randStr += baseStr[Math.floor(Math.random() * baseStr.length)];
}
return randStr;
}
function draw(text,id) {
var qrcode = new QRCode(document.getElementById(id), {
width : 200,
height : 200
});
qrcode.makeCode(text);
}
</script>
</head>
<body>
<div id="content" style="width: 100vw;height: 60vh;display: flex;flex-direction: column;justify-content: center;align-items: center;">
<div id="success_div" style="width: 200px;height: 200px;position: absolute;z-index: 1;background: rgba(0,0,0,0.5);display: none;flex-direction: column;justify-content: center;align-items: center;">
<img src="ic_success.png" width="50" height="50">
<span style="font-size: 90%;color: #ffffff;margin-top: 5px;">扫码成功</span>
</div>
</div>
</body>
</html>
界面显示的话实质上就是一个 二维码,然后就没有了:
接下来就是 手机 扫码时的界面和代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录</title>
</head>
<script type="text/javascript">
var id = "";
var reqId = "";
var ws = {};
window.onload = function(){
var param = window.location.search;
if (param.length > 0) {
param = param.substring(1);
param = param.split("=");
id = param[1];
reqId = createId(10);
ws = new WebSocket("ws://localhost:8080/websocket?openid=" + reqId );
ws.onopen = function() {
// Web Socket 已连接上,使用 send() 方法发送数据
console.log("成功建立连接");
var message = {sendid:id,id:reqId,scan:1};
ws.send(JSON.stringify(message));
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
};
ws.onclose = function(){
// 关闭 websocket
console.log("连接已关闭...");
}
} else {
alert("错误的ID");
}
}
function login(argument) {
console.log("调用登录");
var account = document.getElementById("account").value;
if(account.length == 0){
alert("账号不能为空");
}
var password = document.getElementById("password").value;
if(password.length == 0){
alert("密码不能为空");
}
var message = {sendid:id,id:reqId,account,password};
ws.send(JSON.stringify(message));
return false;
}
function createId(len){
var baseStr = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" + (new Date()).getTime();
var randStr = "";
for(var i = 0; i < len; i++){
randStr += baseStr[Math.floor(Math.random() * baseStr.length)];
}
return randStr;
}
</script>
<body style="width: 100vw;height: 100vh;display: flex;justify-content: center;align-items: center;">
<div >
账号: <input type="text" id="account" value="" placeholder="请输入账号"><br>
密码: <input type="text" id="password" value="" placeholder="请输入密码" style="margin-top: 10px"><br>
<input onclick="login()" type="button" value="提交" style="margin-top: 10px">
</div>
</body>
</html>
这里面楼主没有加加密操作,对于信息较为隐秘的请加密,最后放上服务端的代码:
package com.px.wsserver;
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import net.sf.json.JSONObject;
@ServerEndpoint("/websocket")
public class WsServer {
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String id;
private StringBuffer caheData = new StringBuffer();
public WsServer() {
System.out.println("-----------------------------");
}
/**
* 连接建立成功调用的方法
*
* @param session
* 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
* @throws IOException
*/
@OnOpen
public void onOpen(Session session) throws IOException {
this.session = session;
String url = session.getRequestURI().toString();
int usernameindex = url.indexOf("username=");
int pwdindex = url.indexOf("&pwd=");
int openidindex = url.indexOf("openid=");
if (usernameindex >= 0 && pwdindex >= 0) {
String username = url.substring(usernameindex + "username=".length(), pwdindex);
String pwd = url.substring(pwdindex + "&pwd=".length());
if (!username.equalsIgnoreCase("admin") || !pwd.equalsIgnoreCase("123456")) {
sendMessage("未知用户");
System.out.println("错误用户,断开连接:" + url);
this.Close();
return;
}
id = username + pwd;
if (WsServerManager.existServer(id)) {
sendMessage("该id已连接,请勿重复连接");
System.out.println(id + "已连接,请勿重复连接,断开连接");
id = null;
this.Close();
return;
}
WsServerManager.addWsServer(id, this); // 加入set中
System.out.println("设备 " + id + " 加入!当前在线设备为" + getOnlineCount());
} else if (openidindex >= 0) {
String openid = url.substring(openidindex + "openid=".length());
id = openid;
if (WsServerManager.existServer(id)) {
sendMessage("该id已连接,请勿重复连接");
System.out.println(id + "已连接,请勿重复连接,断开连接");
id = null;
this.Close();
return;
}
WsServerManager.addWsServer(id, this); // 加入set中
System.out.println("设备 " + id + " 加入!当前在线设备为" + getOnlineCount());
} else {
sendMessage("缺少必要参数");
id = null;
this.Close();
return;
}
}
/**
* 连接关闭调用的方法
*
* @throws IOException
*/
@OnClose
public void onClose(Session session) throws IOException {
// 关闭session
if (id == null) {
return;
}
WsServerManager.removeWsServer(id); // 从set中删除
System.out.println("设备 " + id + " 连接关闭!当前在线设备为" + getOnlineCount());
}
public void Close() throws IOException {
// 关闭session
if (session != null && session.isOpen()) {
session.close();
}
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* 客户端发送过来的消息
* @param session
* 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("接收 " + id + " 的消息:" + message);
try {
JSONObject jsonObject = JSONObject.fromObject(message);
String sendid = jsonObject.getString("sendid");
if (sendid != null && sendid.length() > 0) {
WsServer wsserver = WsServerManager.getWsServer(sendid);
if (wsserver == null) {
System.out.println(sendid + " 未连接");
return;
}
wsserver.sendMessage(jsonObject.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
*
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return WsServerManager.getCount();
}
}
package com.px.wsserver;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class WsServerManager {
private static ConcurrentMap<String,WsServer> webSocketSet = new ConcurrentHashMap<String, WsServer>();
private static ConcurrentMap<String,DevInfo> MacDataMap = new ConcurrentHashMap<String, DevInfo>();
public static void addWsServer(String id,WsServer server) {
webSocketSet.put(id, server);
}
public static void addDevInfo(String mac,String Data) {
DevInfo devInfo = MacDataMap.get(mac);
if (devInfo == null) {
devInfo = new DevInfo();
}
devInfo.setMac(mac);
devInfo.setOnline_data(Data);
MacDataMap.put(mac, devInfo);
}
public static DevInfo getDevInfo(String mac) {
return MacDataMap.get(mac);
}
public static WsServer getWsServer(String id) {
return webSocketSet.get(id);
}
public static boolean removeWsServer(String id) throws IOException {
if (webSocketSet.get(id) == null) {
return false;
}
WsServer wsServer = webSocketSet.remove(id);
wsServer.Close();
return true;
}
public static int getCount() {
return webSocketSet.size();
}
public static boolean existServer(String id) {
return webSocketSet.containsKey(id);
}
}
大家有什么问题或有什么更好的建议都已评论出来,一起共同进步