How to Build QR Code Login with WebSocket in Spring Boot
This tutorial walks through designing a QR‑code login flow using Spring Boot, detailing the required database schema, roles, API endpoints, server‑side WebSocket setup, and front‑end JavaScript to fetch the QR image, extract the UUID, and establish a real‑time connection for authentication.
Recently a project required implementing QR‑code login via WebSocket, so this guide shares a complete solution.
1. Database Table
A User_Token table records who scanned the QR code and who logged in.
uuid: ensures uniqueness
userId: identifies the logged‑in user
loginTime: time of login
createTime: creation time for expiration checks
state: QR code status (0 = valid, 1 = invalid)
2. Roles Involved
Android or WeChat web client: scans the QR code
PC client: receives the scan and logs in
Server: orchestrates the process and provides APIs
3. Required APIs
Generate QR code API – creates a QR image containing a UUID
Confirm identity API – validates the UUID, checks expiration, and binds the user
4. Process Steps
PC opens a page and calls the generate‑QR API, establishing a WebSocket link identified by the UUID
The mobile/web client scans the QR code and obtains the UUID from the image header
The client displays a login confirmation page; upon confirmation it calls the confirm‑identity API
If validation succeeds, the server pushes a success message via WebSocket, then closes the link
5. Server‑Side QR Code Generation (Spring Boot)
@RequestMapping(value="/getLoginQr", method=RequestMethod.GET)
public void createCodeImg(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
try {
String uuid = userService.createQrImg();
response.setHeader("uuid", uuid);
QrCodeUtil.generate(uuid, 300, 300, "jpg", response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}The client retrieves the QR image, reads the uuid header, and opens a WebSocket connection using that UUID as the session identifier.
6. Front‑End QR Retrieval and WebSocket Handling
$(document).ready(function(){ initQrImg(); });
function initQrImg(){
$("#qrImgDiv").empty();
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", getQrPath, true);
xmlhttp.responseType = "blob";
xmlhttp.onload = function(){
uuid = this.getResponseHeader("uuid");
if (this.status == 200) {
var blob = this.response;
var img = document.createElement("img");
img.className = 'qrCodeBox-img';
img.onload = function(){ window.URL.revokeObjectURL(img.src); };
img.src = window.URL.createObjectURL(blob);
document.getElementById("qrImgDiv").appendChild(img);
initWebSocket();
}
};
xmlhttp.send();
}
var wsPathStr = wsPath + uuid;
socket = new WebSocket(wsPathStr);
socket.onopen = function(){ console.log("Socket opened"); };
socket.onmessage = function(msg){
var data = JSON.parse(msg.data);
if (data.code == 200) {
alert("Login successful!");
window.sessionStorage.uuid = uuid;
window.sessionStorage.userId = data.userId;
window.sessionStorage.projId = data.projId;
window.location.href = "pages/upload.html";
} else {
socket.close();
initQrImg();
}
};
socket.onclose = function(){ console.log("Socket closed"); };
socket.onerror = function(){ alert("Socket error"); };7. Spring Boot WebSocket Configuration
Add the WebSocket starter dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>Define a bean to enable WebSocket support:
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}Implement the WebSocket server:
@ServerEndpoint("/websocket/{sid}")
@Component
public class WebSocketServer {
private static int onlineCount = 0;
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
private Session session;
private String sid = "";
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
this.session = session;
webSocketSet.add(this);
addOnlineCount();
this.sid = sid;
}
@OnClose
public void onClose() {
webSocketSet.remove(this);
subOnlineCount();
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
for (WebSocketServer item : webSocketSet) {
item.sendMessage(message);
}
}
@OnError
public void onError(Session session, Throwable error) { error.printStackTrace(); }
public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); }
public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
for (WebSocketServer item : webSocketSet) {
if (sid == null || item.sid.equals(sid)) {
item.sendMessage(message);
}
}
}
// synchronized counters omitted for brevity
}8. Confirm Identity API
@RequestMapping(value="/bindUserIdAndToken", method=RequestMethod.GET)
@ResponseBody
public Object bindUserIdAndToken(@RequestParam("token") String token,
@RequestParam("userId") Integer userId,
@RequestParam(required=false, value="projId") Integer projId) {
try {
return new SuccessTip(userService.bindUserIdAndToken(userId, token, projId));
} catch (Exception e) {
e.printStackTrace();
return new ErrorTip(500, e.getMessage());
}
}The service validates the token, checks expiration, updates the login record, and pushes a JSON message to the client via WebSocketServer.sendInfo. If the token is invalid or expired, an error is returned and the client is notified.
Knowledge point: dynamically load image streams and extract header parameters.
With these components, the QR‑code login flow works: the PC displays a QR image, the mobile client scans it, the server validates the token, and a WebSocket message notifies the PC of successful authentication.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
