二维码登录原理
让服务端知道是那个用户要登录,验证通过后 服务端通过webscoket 告知 前端 登录成功即可
前端二维码登录实现
链接: 仿知乎pc登录注册二维码登录页面.
下载下来修改一下即可使用
index.html 按上图位置添加这一行代码:
<br>当前二维码串是:<span id="qrCode"> </span><br>
在login.js 直接复制下面代码进行覆盖即可
$(function () {
// tabSwicth
let phoneTabcont = $(".tabContentPhone");
let accountTabcont = $(".tabContentAccount");
$("ul.tabBoxSwitchUl").on('click', 'li', function () {
let i = $(this).index();
// $(this).attr("data-id",i);
// console.log(i);
$(this).addClass("tab-active").siblings('li').removeClass("tab-active");
$("div.tabcont").eq(i).addClass("active").siblings().removeClass("active");
// let module;//smsFrom accountFrom
formType(i);
});
function formType(i) {
if (i == 0) {
$("form").attr("data-module", "smsFrom");
$("form button.voice-btn").attr("data-btn", "sms-voice-btn").text("接收语音验证码");
$("form button.out-login-btn").hide();
$("form button.fromSubmit").attr("data-type", "smsSubmit").text("注册/登录");
} else if (i == 1) {
$("form").attr("data-module", "accountFrom");
$("form button.voice-btn").attr("data-btn", "account-forget-btn").text("忘记密码");
$("form button.out-login-btn").show();
$("form button.fromSubmit").attr("data-type", "accountSubmit").text("登录");
forgeClick();
}
}
// 密码登录:海外手机/账号
$("button[data-clilck='isClick']").click(function (e) {
e.preventDefault();
let _this = $(this);
let _show = $(".login-out-phoneBox");
if (_show.is(':hidden')) {
_show.show()
_this.text("邮箱账号登录");
} else {
_show.hide()
_this.text("海外手机号登录");
}
});
// 忘记密码点击
// 语音服务
$("button[data-btn='sms-voice-btn']").click(function (e) {
e.preventDefault;
console.log("语音服务");
});
var forgeClick = function () {
$("button[data-btn='account-forget-btn']").click(function (e) {
e.preventDefault;
// window.open("http://www.baidu.com");//忘记密码页面
alert("前往忘记密码页");
});
}
$("button.selectBtn").click(function (e) {
if ($(".selectConentent").is(':hidden')) {
$(".selectConentent").show();
} else {
$(".selectConentent").hide();
}
$(document).one('click', function () {
$(".selectConentent").hide();
});
e.stopPropagation();
});
$(".selectConentent").on('click', function (e) {
e.stopPropagation();
})
// 国际区号json
$.ajax({
type: "GET",
url: "../js/selectOptions.json",
data: "data",
dataType: "JSON",
success: function (data) {
// console.log(data);
$.each(data.CountryNum, function (i, item) {
// console.log(item.countryName, item.number);
let btns = " <button class='phone-btn selectBtn select-option' type='button' data-type='option'" + "data-id=" + i + ">" + item.countryName + " " + item.number + "</button>";
$(".selectOptions").append(btns);
chooseBtn();
// console.log(btns);
});
}
});
function chooseBtn() {
$("button[data-type='option']").each(function () {
$(this).click(function () {
let txt = $(this).text();
$("button[data-type='selected']").attr("data-fid", $(this).index());
$("button[data-type='selected'] span").text(txt);
$(".selectConentent").hide();
$(".selectOptions").scrollTop($(this).index() * 40);
});
$(this).hover(function () {
$(this).css("background-color", "#f6f6f6");
}, function () {
$(this).css("background-color", "#ffffff");
});
});
};
//失去焦点;获得焦点
Focuss($(".msgInput"), "输入 6 位短信验证码");
Focuss($(".phoneInput"), "手机号");
Focuss($(".accountUsername"), "手机号或邮箱");
Focuss($(".accountPwd"), "密码");
Blurr($(".phoneInput"), "请输入手机号");
Blurr($(".msgInput"), "请输入短信验证码");
Blurr($(".accountUsername"), "请输入手机号或邮箱");
Blurr($(".accountPwd"), "请输入密码");
function Focuss(ele, content) {
ele.focus(function (e) {
e.preventDefault();
let _this = $(this);
_this.parent().removeClass('isShow');
_this.attr("placeholder", content);
})
}
function Blurr(eleb, contentb) {
eleb.blur(function (e) {
e.preventDefault();
let _this = $(this);
if (_this.val() == null || _this.val() == "" || _this.val() == undefined) {
// let content = "请输入短信验证码"
_this.parent().addClass('isShow').attr('data-content', contentb);
_this.attr("placeholder", " ");
} else {
_this.parent().removeClass('isShow');
}
})
}
// 60s倒计时
$(".msgBtn").click(function () {
let pval = $(".phoneInput").val();
if (pval == "" || pval == null || pval == undefined) {
$(".msgBtn").text("重新发送短信验证码");
let content = "请输入手机号";
$(".phoneInput").parent().addClass('isShow').attr('data-content', content);
$(".phoneInput").attr("placeholder", " ");
} else {
$(".msgBtn").css("color", "#b7b7b7");
$(".msgBtn").attr("disabled", true);
getRandom();
}
// getRandom();
})
var time = 60;
function getRandom() {
if (time === 0) {
$(".msgBtn").text("发送短信验证码");
$(".msgBtn").css("color", "#175199");
$(".msgBtn").attr("disabled", false);
return
} else {
time--;
$(".msgBtn").text(time + " 秒后可重发");
}
setTimeout(function () {
getRandom();
}, 1000)
}
// ercode tab
$(".swicth-ercode").click(function (e) {
e.preventDefault();
$("form#form_key").hide();
$(".ercodeSignBox").show();
alert("成功连接WebSocket");
WebSocketTest();
});
$(".switch-input").click(function (e) {
e.preventDefault();
$("form#form_key").show();
$(".ercodeSignBox").hide();
webscoketClose();
});
//ercode
var qrcode = new QRCode('qrcode', {
text: '',
width: 150,
height: 150,
colorDark: '#0084ff',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
function makeCode(txt) {
qrcode.clear();
qrcode.makeCode(txt);
}
var ws = null;
var uri = "ws://127.0.0.1:8080/ws";
function WebSocketTest(){
if ("WebSocket" in window){
createWebSocket();
}else{
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
/**
* 创建websocket
*/
function createWebSocket() {
alert("开启长连接")
// 打开一个 web socket
ws = new WebSocket(uri);
ws.onopen = function(){
};
ws.onmessage = function (evt){
var received_msg = evt.data;
if(received_msg == "ok"){
console.log(received_msg);
alert("登录成功了");
}else{
makeCode(received_msg);
document.getElementById("qrCode").innerText= received_msg;
}
};
ws.onclose = function(){
webscoketClose();
};
}
/**
* websocket关闭
*/
function webscoketClose() {
ws.close();
console.log("websocket关闭");
}
function sendMsg(str){
if(ws.readyState == 1){
ws.send(str);
}else{
alert("未连接上服务器");
}
}
});
java后端代码
springboot整合webscoket长连接(主要实现)
import com.zm.scanlogin.base.SessionIdHashMap;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
@Component
@ServerEndpoint(value = "/ws")
public class WebSocketServer {
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String qrCodeString;
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<>();
private Timer timer = new Timer();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
SessionSet.add(session);
this.session = session;
int cnt = OnlineCount.incrementAndGet(); // 在线数加1
System.out.println("有连接加入,当前连接数为:" + cnt);
heartBeat(session);
String qrCodeString = String.valueOf(System.currentTimeMillis());
this.qrCodeString = qrCodeString;
SendMessage(this.session,this.qrCodeString);
SessionIdHashMap.getInstance().put(this.qrCodeString,session.getId());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
SessionIdHashMap.getInstance().remove(this.qrCodeString);
SessionSet.remove(this.session);
int cnt = OnlineCount.decrementAndGet();
System.out.println("有连接关闭,当前连接数为:" + cnt);
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
}
/**
* 出现错误
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
/**
* 2分钟断线,让前端主动触发重连接口----刷新二维码
* @param session
*/
private void heartBeat(Session session) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}, 180_000);
}
/**
* 发送消息
*
* @param session
* @param message
*/
public static void SendMessage(Session session, String message) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendText(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 群发消息
*
* @param message
* @throws IOException
*/
public static void BroadCastInfo(String message) {
for (Session session : SessionSet) {
SendMessage(session, message);
}
}
/**
* 指定Session发送消息
*
* @param sessionId
* @param message
* @throws IOException
*/
public static void SendMessage(String message, String sessionId) {
Session session = null;
for (Session s : SessionSet) {
if (s.getId().equals(sessionId)) {
session = s;
break;
}
}
if (session != null) {
SendMessage(session, message);
}
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket配置
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter () {
return new ServerEndpointExporter();
}
}
import java.util.concurrent.ConcurrentHashMap;
public class SessionIdHashMap {
/**
* 用来存放每个二维码串对应的Session对象
* key qrCode
* value SessionId
*/
private static ConcurrentHashMap<String,String> sessionIdHashMap = new ConcurrentHashMap<>();
private SessionIdHashMap(){
}
public static ConcurrentHashMap<String,String> getInstance(){
return sessionIdHashMap;
}
}
import com.zm.scanlogin.base.SessionIdHashMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
@RestController
public class QrLoginController {
@GetMapping("qr_login")
public String qrLogin(@RequestParam("qrCode")String qrCode) {
String sessionId = SessionIdHashMap.getInstance().get(qrCode);
if(Optional.ofNullable(sessionId).isPresent()){
// message 可以使用JSONString 传输
WebSocketServer.SendMessage("ok",sessionId);
return "扫码成功,返回用户token";
}
return "扫码失败,二维码无效";
}
}
用postman 模拟PC端 解析二维码并发起登录请求
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/133939.html