网站首页 > 技术文章 正文
SpringBoot2 二维码扫码登录原理与代码实战详解
首先,我需要回忆一下二维码登录的一般流程。通常,这种登录方式在微信、支付宝等应用中常见,用户用手机扫描网页上的二维码,然后手机端确认登录,网页端随即登录成功。
那原理部分,可能需要分步骤讲解。首先,网页生成二维码,里面包含一个唯一的标识,比如token或者UUID,并且这个标识需要与服务器建立某种关联,比如存储在Redis中,设置过期时间。然后,手机扫描二维码后,获取这个标识,并发送到服务器进行验证。服务器确认后,将用户信息与该标识绑定,网页端通过轮询或WebSocket等方式检测到状态变化,完成登录。
接下来是代码部分。用户可能希望看到具体的实现步骤,所以需要分模块讲解。比如,生成二维码的接口,处理扫码确认的接口,以及网页端的轮询接口。可能需要用到Spring Boot的Web模块,还有Redis作为存储,可能用到了WebSocket或者轮询机制。
需要注意的点:二维码的有效期管理,防止重复扫描,安全性问题比如token的随机性,防止伪造。还有,如何将用户信息与token关联,比如用户扫描后,手机端可能已经登录,如何获取用户信息绑定到token上,这里可能需要手机端的配合,但在代码实战中,可能需要模拟这个过程。
另外,在代码示例中,可能需要用到生成二维码的库,比如Google的ZXing库,或者其他的Java二维码生成工具。在Spring Boot中如何整合这些库,生成二维码图片返回给前端。
还有,前端部分如何展示二维码,并定时轮询后端接口,检查登录状态。前端可能使用JavaScript定时发送请求,或者使用WebSocket实时通信。
可能用户还关心异常处理,比如二维码过期后如何处理,重复扫描的提示,以及安全性措施,比如HTTPS的使用,token的加密传输等。
在写代码的时候,需要注意模块划分,比如Controller层处理请求,Service层处理业务逻辑,Redis的操作可能需要用到Spring Data Redis。还需要考虑接口的设计,比如生成二维码的接口返回什么数据,轮询接口的返回状态码设计等。
可能还需要考虑跨域问题,如果前端和后端分离的话,需要配置CORS。不过如果是同源的话,可能不需要。
总结一下,回答的结构应该是先讲原理,分步骤说明整个流程,然后给出Spring Boot 2的代码实现,包括依赖配置、生成二维码、处理扫描确认、轮询检查状态等部分,最后可能给出一些注意事项和扩展建议。
二维码扫码登录是一种常见的身份验证方式,广泛应用于Web和移动端。以下是Spring Boot 2实现二维码扫码登录的核心原理及代码实战详解。
一、扫码登录核心原理
- 流程概述
- 生成二维码:服务端生成唯一ID(如UUID)并与登录状态绑定,返回给前端生成二维码。
- 手机扫码:用户使用已登录的APP扫描二维码,将用户身份与二维码ID绑定。
- 状态轮询:网页端通过轮询或WebSocket实时检测登录状态,完成登录跳转。
- 关键技术点
- 唯一性标识:使用UUID或Token标识每个二维码。
- 状态存储:Redis存储二维码状态(未扫描/已确认/过期)。
- 实时通信:WebSocket或HTTP轮询实现状态同步。
二、Spring Boot 2 代码实战
1. 环境准备
依赖配置(pom.xml)
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 二维码生成库 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
2. 生成二维码接口
Controller层
@RestController
@RequestMapping("/qrcode")
public class QrCodeController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/generate")
public ResponseEntity<byte[]> generateQrCode() throws Exception {
String qrCodeId = UUID.randomUUID().toString();
// 存储二维码状态:0-未扫描,1-已扫描待确认,2-已确认
redisTemplate.opsForValue().set(qrCodeId, "0", 5, TimeUnit.MINUTES);
// 生成二维码内容(例如包含qrCodeId)
String content = "login:" + qrCodeId;
ByteArrayOutputStream outputStream = QRCodeUtils.generateQrCode(content, 300, 300);
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(outputStream.toByteArray());
}
}
工具类QRCodeUtils
public class QRCodeUtils {
public static ByteArrayOutputStream generateQrCode(String content, int width, int height) throws WriterException, IOException {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(matrix, "PNG", outputStream);
return outputStream;
}
}
3. 手机端扫码确认
模拟APP扫码后调用确认接口
@PostMapping("/confirm")
public ResponseEntity<String> confirmLogin(@RequestParam String qrCodeId, @RequestParam String userId) {
String status = redisTemplate.opsForValue().get(qrCodeId);
if ("0".equals(status)) {
// 更新状态为已扫描待确认
redisTemplate.opsForValue().set(qrCodeId, "1");
// 绑定用户ID(实际场景需从APP登录态获取)
redisTemplate.opsForValue().set(qrCodeId + ":user", userId);
return ResponseEntity.ok("等待用户确认");
}
return ResponseEntity.badRequest().body("二维码已失效");
}
4. 网页端轮询状态
轮询接口
@GetMapping("/check")
public ResponseEntity<Map<String, String>> checkStatus(@RequestParam String qrCodeId) {
String status = redisTemplate.opsForValue().get(qrCodeId);
Map<String, String> result = new HashMap<>();
if (status == null) {
result.put("status", "expired");
} else if ("1".equals(status)) {
result.put("status", "confirmed");
// 获取用户信息
String userId = redisTemplate.opsForValue().get(qrCodeId + ":user");
result.put("userId", userId);
// 清除Redis数据
redisTemplate.delete(qrCodeId);
redisTemplate.delete(qrCodeId + ":user");
} else {
result.put("status", status); // 0-未扫描,1-已扫描
}
return ResponseEntity.ok(result);
}
5. 前端轮询逻辑(JavaScript示例)
let qrCodeId = "生成的二维码ID";
let poll = setInterval(() => {
fetch(`/qrcode/check?qrCodeId=${qrCodeId}`)
.then(response => response.json())
.then(data => {
if (data.status === 'confirmed') {
clearInterval(poll);
alert('登录成功,用户ID:' + data.userId);
} else if (data.status === 'expired') {
clearInterval(poll);
alert('二维码已过期');
}
});
}, 2000); // 每2秒轮询一次
三、关键优化与注意事项
- 安全性
- Token加密:二维码内容使用JWT加密防止伪造。
- HTTPS:全程使用HTTPS防止中间人攻击。
- 性能优化
- WebSocket替代轮询:减少HTTP请求开销。
- Redis过期时间:合理设置二维码有效期(通常2-5分钟)。
- 用户体验
- 扫码提示:根据状态返回不同提示(如“请点击APP确认”)。
- 自动跳转:检测到登录成功后自动跳转至首页。
通过上述代码和原理分析,可实现完整的二维码扫码登录功能。实际项目中需结合具体业务调整用户信息绑定和安全性策略。
猜你喜欢
- 2025-05-08 谁还需要团队?单人开发者的黑科技三板斧:AI视频×一行代码接支付
- 2025-05-08 新手学习前端开发的正确打开方式(前端如何开发)
- 2025-05-08 简单解析一下扫码登陆原理(扫码登录操作)
- 2025-05-08 怎么制作二维码分班查询系统?(二维码查询分班信息)
- 2025-05-08 odooapp普通动态二维码全网通扫识别打开
- 2025-05-08 Spring Boot3 扫码登录实现全解析:从基础到实战
- 2024-09-18 前端开发之移动端开发包
- 2024-09-18 4.1k star!Painter,小程序图片生成的神器!不仅仅支持小程序
- 2024-09-18 前端车牌识别OCR算法
- 2024-09-18 EL-ADMIN前端代码从0手写--Vue+ElemenUI
你 发表评论:
欢迎- 06-24发现一款开源宝藏级工作流低代码快速开发平台
- 06-24程序员危险了,这是一个 无代码平台+AI+code做项目的案例
- 06-24一款全新的工作流,低代码快速开发平台
- 06-24如何用好AI,改造自己的设计工作流?
- 06-24濮阳网站开发(濮阳网站建设)
- 06-24AI 如何重塑前端开发,我们该如何适应
- 06-24应届生靠这个Java简历模板拿下了5个offer
- 06-24服务端性能测试实战3-性能测试脚本开发
- 567℃几个Oracle空值处理函数 oracle处理null值的函数
- 566℃Oracle分析函数之Lag和Lead()使用
- 550℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 545℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 543℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 536℃【数据统计分析】详解Oracle分组函数之CUBE
- 526℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 519℃Oracle有哪些常见的函数? oracle中常用的函数
- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)