From 630935f0f5f48e7f6838c5e61d10b0380229272b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Mon, 8 Sep 2025 08:01:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor(qr-login):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 LocalDateTime 替换为 Date 类型- 优化日期处理逻辑,使用 DateUtil 工具类 - 调整日志输出格式 - 重构部分代码结构,提高可读性 --- .../com/gxwebsoft/auto/dto/QrLoginData.java | 6 +- .../auto/service/impl/QrLoginServiceImpl.java | 307 +++++++++--------- 2 files changed, 158 insertions(+), 155 deletions(-) diff --git a/src/main/java/com/gxwebsoft/auto/dto/QrLoginData.java b/src/main/java/com/gxwebsoft/auto/dto/QrLoginData.java index 563bf1d..4d76b40 100644 --- a/src/main/java/com/gxwebsoft/auto/dto/QrLoginData.java +++ b/src/main/java/com/gxwebsoft/auto/dto/QrLoginData.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.time.LocalDateTime; +import java.util.Date; /** * 扫码登录数据模型 @@ -40,12 +40,12 @@ public class QrLoginData { /** * 创建时间 */ - private LocalDateTime createTime; + private Date createTime; /** * 过期时间 */ - private LocalDateTime expireTime; + private Date expireTime; /** * JWT访问令牌(确认后生成) diff --git a/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java b/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java index bd2aee7..b361e5c 100644 --- a/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java +++ b/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java @@ -1,5 +1,7 @@ package com.gxwebsoft.auto.service.impl; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.util.StrUtil; import com.gxwebsoft.auto.dto.*; @@ -30,175 +32,176 @@ import static com.gxwebsoft.common.core.constants.RedisConstants.*; @Service public class QrLoginServiceImpl implements QrLoginService { - @Autowired - private RedisUtil redisUtil; + @Autowired + private RedisUtil redisUtil; - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Value("${config.jwt.secret:websoft-jwt-secret-key-2025}") - private String jwtSecret; + @Value("${config.token-key}") + private String tokenKey; - @Value("${config.jwt.expire:86400}") - private Long jwtExpire; + @Value("${config.token-expire-time:86400}") + private Long tokenExpireTime; - @Override - public QrLoginGenerateResponse generateQrLoginToken() { - // 生成唯一的扫码登录token - String token = UUID.randomUUID().toString(true); + @Override + public QrLoginGenerateResponse generateQrLoginToken() { + // 生成唯一的扫码登录token + String token = UUID.randomUUID().toString(true); - // 创建扫码登录数据 - QrLoginData qrLoginData = new QrLoginData(); - qrLoginData.setToken(token); - qrLoginData.setStatus(QR_LOGIN_STATUS_PENDING); - qrLoginData.setCreateTime(LocalDateTime.now()); - qrLoginData.setExpireTime(LocalDateTime.now().plusSeconds(QR_LOGIN_TOKEN_TTL)); + // 创建扫码登录数据 + QrLoginData qrLoginData = new QrLoginData(); + qrLoginData.setToken(token); + qrLoginData.setStatus(QR_LOGIN_STATUS_PENDING); + // 五分钟过期 + qrLoginData.setExpireTime(DateUtil.offsetSecond(DateUtil.date(), QR_LOGIN_TOKEN_TTL.intValue())); - // 存储到Redis,设置过期时间 - String redisKey = QR_LOGIN_TOKEN_KEY + token; - redisUtil.set(redisKey, qrLoginData, QR_LOGIN_TOKEN_TTL, TimeUnit.SECONDS); + // 存储到Redis,设置过期时间 + String redisKey = QR_LOGIN_TOKEN_KEY + token; + redisUtil.set(redisKey, qrLoginData, QR_LOGIN_TOKEN_TTL, TimeUnit.SECONDS); - log.info("生成扫码登录token: {}", token); + log.info("生成扫码登录token: {}", token); - // 构造二维码内容(这里可以是前端登录页面的URL + token参数) - String qrCodeContent = "qr-login:" + token; + // 构造二维码内容(这里可以是前端登录页面的URL + token参数) + String qrCodeContent = "qr-login:" + token; - return new QrLoginGenerateResponse(token, qrCodeContent, QR_LOGIN_TOKEN_TTL); + return new QrLoginGenerateResponse(token, qrCodeContent, QR_LOGIN_TOKEN_TTL); + } + + @Override + public QrLoginStatusResponse checkQrLoginStatus(String token) { + if (StrUtil.isBlank(token)) { + return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); } - @Override - public QrLoginStatusResponse checkQrLoginStatus(String token) { - if (StrUtil.isBlank(token)) { - return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); - } + String redisKey = QR_LOGIN_TOKEN_KEY + token; + QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); - String redisKey = QR_LOGIN_TOKEN_KEY + token; - QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); - - if (qrLoginData == null) { - return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); - } - - // 检查是否过期 - if (LocalDateTime.now().isAfter(qrLoginData.getExpireTime())) { - // 删除过期的token - redisUtil.delete(redisKey); - return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); - } - - // 计算剩余过期时间 - long expiresIn = ChronoUnit.SECONDS.between(LocalDateTime.now(), qrLoginData.getExpireTime()); - - QrLoginStatusResponse response = new QrLoginStatusResponse(); - response.setStatus(qrLoginData.getStatus()); - response.setExpiresIn(expiresIn); - - // 如果已确认,返回token和用户信息 - if (QR_LOGIN_STATUS_CONFIRMED.equals(qrLoginData.getStatus())) { - response.setAccessToken(qrLoginData.getAccessToken()); - - // 获取用户信息 - if (qrLoginData.getUserId() != null) { - User user = userService.getByIdRel(qrLoginData.getUserId()); - if (user != null) { - // 清除敏感信息 - user.setPassword(null); - response.setUserInfo(user); - } - } - - // 确认后删除token,防止重复使用 - redisUtil.delete(redisKey); - } - - return response; + if (qrLoginData == null) { + return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); } - @Override - public QrLoginStatusResponse confirmQrLogin(QrLoginConfirmRequest request) { - String token = request.getToken(); - Integer userId = request.getUserId(); - - if (StrUtil.isBlank(token) || userId == null) { - throw new RuntimeException("参数不能为空"); - } - - String redisKey = QR_LOGIN_TOKEN_KEY + token; - QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); - - if (qrLoginData == null) { - throw new RuntimeException("扫码登录token不存在或已过期"); - } - - // 检查是否过期 - if (LocalDateTime.now().isAfter(qrLoginData.getExpireTime())) { - redisUtil.delete(redisKey); - throw new RuntimeException("扫码登录token已过期"); - } - - // 获取用户信息 - User user = userService.getByIdRel(userId); - if (user == null) { - throw new RuntimeException("用户不存在"); - } - - // 检查用户状态 - if (user.getStatus() != null && user.getStatus() != 0) { - throw new RuntimeException("用户已被冻结"); - } - - // 生成JWT token - JwtSubject jwtSubject = new JwtSubject(user.getUsername(), user.getTenantId()); - String accessToken = JwtUtil.buildToken(jwtSubject, jwtExpire, jwtSecret); - - // 更新扫码登录数据 - qrLoginData.setStatus(QR_LOGIN_STATUS_CONFIRMED); - qrLoginData.setUserId(userId); - qrLoginData.setUsername(user.getUsername()); - qrLoginData.setAccessToken(accessToken); - - // 更新Redis中的数据 - redisUtil.set(redisKey, qrLoginData, 60L, TimeUnit.SECONDS); // 给前端60秒时间获取token - - log.info("用户 {} 确认扫码登录,token: {}", user.getUsername(), token); - - // 清除敏感信息 - user.setPassword(null); - - return new QrLoginStatusResponse(QR_LOGIN_STATUS_CONFIRMED, accessToken, user, 60L); + // 检查是否过期 + // 替换第85行代码为以下内容: + if (LocalDateTime.now().isAfter(DateUtil.toLocalDateTime(qrLoginData.getExpireTime()))) { + // 删除过期的token + redisUtil.delete(redisKey); + return new QrLoginStatusResponse(QR_LOGIN_STATUS_EXPIRED, null, null, 0L); } - @Override - public boolean scanQrCode(String token) { - if (StrUtil.isBlank(token)) { - return false; + // 计算剩余过期时间 + long expiresIn = ChronoUnit.SECONDS.between(LocalDateTime.now(), DateUtil.toLocalDateTime(qrLoginData.getExpireTime())); + + QrLoginStatusResponse response = new QrLoginStatusResponse(); + response.setStatus(qrLoginData.getStatus()); + response.setExpiresIn(expiresIn); + + // 如果已确认,返回token和用户信息 + if (QR_LOGIN_STATUS_CONFIRMED.equals(qrLoginData.getStatus())) { + response.setAccessToken(qrLoginData.getAccessToken()); + + // 获取用户信息 + if (qrLoginData.getUserId() != null) { + User user = userService.getByIdRel(qrLoginData.getUserId()); + if (user != null) { + // 清除敏感信息 + user.setPassword(null); + response.setUserInfo(user); } + } - String redisKey = QR_LOGIN_TOKEN_KEY + token; - QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); - - if (qrLoginData == null) { - return false; - } - - // 检查是否过期 - if (LocalDateTime.now().isAfter(qrLoginData.getExpireTime())) { - redisUtil.delete(redisKey); - return false; - } - - // 只有pending状态才能更新为scanned - if (QR_LOGIN_STATUS_PENDING.equals(qrLoginData.getStatus())) { - qrLoginData.setStatus(QR_LOGIN_STATUS_SCANNED); - - // 计算剩余过期时间 - long remainingSeconds = ChronoUnit.SECONDS.between(LocalDateTime.now(), qrLoginData.getExpireTime()); - redisUtil.set(redisKey, qrLoginData, remainingSeconds, TimeUnit.SECONDS); - - log.info("扫码登录token {} 状态更新为已扫码", token); - return true; - } - - return false; + // 确认后删除token,防止重复使用 + redisUtil.delete(redisKey); } + + return response; + } + + @Override + public QrLoginStatusResponse confirmQrLogin(QrLoginConfirmRequest request) { + String token = request.getToken(); + Integer userId = request.getUserId(); + + if (StrUtil.isBlank(token) || userId == null) { + throw new RuntimeException("参数不能为空"); + } + + String redisKey = QR_LOGIN_TOKEN_KEY + token; + QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); + + if (qrLoginData == null) { + throw new RuntimeException("扫码登录token不存在或已过期"); + } + + // 检查是否过期 + if (LocalDateTime.now().isAfter(DateUtil.toLocalDateTime(qrLoginData.getExpireTime()))) { + redisUtil.delete(redisKey); + throw new RuntimeException("扫码登录token已过期"); + } + + // 获取用户信息 + User user = userService.getAllByUserId(String.valueOf(userId)); + if (user == null) { + throw new RuntimeException("用户不存在"); + } + + // 检查用户状态 + if (user.getStatus() != null && user.getStatus() != 0) { + throw new RuntimeException("用户已被冻结"); + } + + // 生成JWT token + JwtSubject jwtSubject = new JwtSubject(user.getUsername(), user.getTenantId()); + String accessToken = JwtUtil.buildToken(jwtSubject, tokenExpireTime, tokenKey); + + // 更新扫码登录数据 + qrLoginData.setStatus(QR_LOGIN_STATUS_CONFIRMED); + qrLoginData.setUserId(userId); + qrLoginData.setUsername(user.getUsername()); + qrLoginData.setAccessToken(accessToken); + + // 更新Redis中的数据 + redisUtil.set(redisKey, qrLoginData, 60L, TimeUnit.SECONDS); // 给前端60秒时间获取token + + log.info("用户 {} 确认扫码登录,token: {}", user.getUsername(), token); + + // 清除敏感信息 + user.setPassword(null); + + return new QrLoginStatusResponse(QR_LOGIN_STATUS_CONFIRMED, accessToken, user, 60L); + } + + @Override + public boolean scanQrCode(String token) { + if (StrUtil.isBlank(token)) { + return false; + } + + String redisKey = QR_LOGIN_TOKEN_KEY + token; + QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class); + + if (qrLoginData == null) { + return false; + } + + // 检查是否过期 + if (LocalDateTime.now().isAfter(DateUtil.toLocalDateTime(qrLoginData.getExpireTime()))) { + redisUtil.delete(redisKey); + return false; + } + + // 只有pending状态才能更新为scanned + if (QR_LOGIN_STATUS_PENDING.equals(qrLoginData.getStatus())) { + qrLoginData.setStatus(QR_LOGIN_STATUS_SCANNED); + + // 计算剩余过期时间 + long remainingSeconds = ChronoUnit.SECONDS.between(LocalDateTime.now(), DateUtil.toLocalDateTime(qrLoginData.getExpireTime())); + redisUtil.set(redisKey, qrLoginData, remainingSeconds, TimeUnit.SECONDS); + + log.info("扫码登录token {} 状态更新为已扫码", token); + return true; + } + + return false; + } }