From 3ffd3255eed15c1934ef0a6bf01292fd582ce4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 24 Jul 2026 20:28:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(auth):=20=E4=BF=AE=E5=A4=8D=E9=82=AE?= =?UTF-8?q?=E7=AE=B1=E7=99=BB=E5=BD=95SQL=E5=88=AB=E5=90=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=B9=B6=E6=94=AF=E6=8C=81=E9=82=AE=E7=AE=B1=E6=89=BE?= =?UTF-8?q?=E5=9B=9E=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserMapper.selectAccountsByEmail 修正 FROM 别名 a 与 WHERE 中 u.is_super_admin 不匹配导致的 BadSqlGrammarException - 去掉邮箱查询的管理员限定(邮箱已全局唯一,邮箱登录不再限管理员) - 重置密码接口支持邮箱+邮箱验证码找回方式 --- .../system/controller/MainController.java | 80 ++++++++++++------- .../common/system/mapper/xml/UserMapper.xml | 13 ++- .../system/param/ResetPasswordParam.java | 12 ++- 3 files changed, 70 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java index 5b740d5..a26531e 100644 --- a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java +++ b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java @@ -1489,17 +1489,20 @@ public class MainController extends BaseController { /** * 重置密码(找回密码功能) + * 支持两种验证方式:手机号+短信验证码 / 邮箱+邮箱验证码 * 支持两种模式: * 1. 传 userId + tenantId:精确重置指定账号密码 - * 2. 不传 userId:通过手机号查找所有正常账号,统一重置密码(忘记密码场景) + * 2. 不传 userId:通过手机号/邮箱查找所有正常账号,统一重置密码(忘记密码场景) */ @Operation(summary = "重置密码") @PostMapping("/resetPassword") @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE) public ApiResult resetPassword(@RequestBody ResetPasswordParam param) { - // 验证手机号 - if (!CommonUtil.isValidPhoneNumber(param.getPhone())) { - return fail("请输入有效的手机号码"); + // 判断找回方式:邮箱 or 手机 + boolean byEmail = StrUtil.isNotBlank(param.getEmail()); + boolean byPhone = StrUtil.isNotBlank(param.getPhone()); + if (!byEmail && !byPhone) { + return fail("请提供手机号或邮箱"); } // 验证两次密码是否一致 @@ -1512,21 +1515,42 @@ public class MainController extends BaseController { return fail("密码必须至少8位,且包含字母和数字"); } - // 验证短信验证码 - String key = "code:" + param.getPhone(); - String cachedCode = redisUtil.get(key); - String devCode = redisUtil.get(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS); - - if (!param.getSmsCode().equals(cachedCode) && !param.getSmsCode().equals(devCode)) { - return fail("短信验证码不正确"); + // ===== 验证码校验 ===== + String verifyKey; + String inputCode; + if (byEmail) { + if (!CommonUtil.isValidEmail(param.getEmail())) { + return fail("请输入有效的邮箱地址"); + } + if (StrUtil.isBlank(param.getEmailCode())) { + return fail("邮箱验证码不能为空"); + } + verifyKey = RedisConstants.EMAIL_CODE_KEY + ":" + param.getEmail(); + inputCode = param.getEmailCode(); + } else { + if (!CommonUtil.isValidPhoneNumber(param.getPhone())) { + return fail("请输入有效的手机号码"); + } + if (StrUtil.isBlank(param.getSmsCode())) { + return fail("短信验证码不能为空"); + } + verifyKey = "code:" + param.getPhone(); + inputCode = param.getSmsCode(); } - // ===== 模式判断:userId 为空时按手机号查所有用户统一重置 ===== + String cachedCode = redisUtil.get(verifyKey); + String devCode = redisUtil.get(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS); + if (!inputCode.equals(cachedCode) && !inputCode.equals(devCode)) { + return fail(byEmail ? "邮箱验证码不正确" : "短信验证码不正确"); + } + + // ===== 模式判断:userId 为空时按手机号/邮箱查所有用户统一重置 ===== if (StrUtil.isBlank(param.getUserId())) { - // 通过手机号查找所有用户(跨租户,忽略租户隔离) - List userList = userMapper.selectAccountsByPhone(param.getPhone()); + List userList = byEmail + ? userMapper.selectAccountsByEmail(param.getEmail()) + : userMapper.selectAccountsByPhone(param.getPhone()); if (userList == null || userList.isEmpty()) { - return fail("该手机号未注册"); + return fail(byEmail ? "该邮箱未注册" : "该手机号未注册"); } // 过滤掉被冻结的账号 List activeUsers = userList.stream() @@ -1535,8 +1559,9 @@ public class MainController extends BaseController { if (activeUsers.isEmpty()) { return fail("账号已被冻结,请联系管理员"); } - // 统一重置所有同手机号的正常账号密码 + // 统一重置所有正常账号密码 String encodedPassword = userService.encodePassword(param.getNewPassword()); + String methodDesc = byEmail ? "通过邮箱" : "通过手机号"; for (User u : activeUsers) { User update = new User(); update.setUserId(u.getUserId()); @@ -1547,23 +1572,28 @@ public class MainController extends BaseController { record.setUsername(u.getUsername()); record.setNickname(u.getNickname()); record.setLoginType(5); - record.setComments("密码重置成功(通过手机号)"); + record.setComments("密码重置成功(" + methodDesc + ")"); record.setTenantId(u.getTenantId()); loginRecordService.save(record); } - redisUtil.delete(key); + redisUtil.delete(verifyKey); return success("密码重置成功"); } // ===== 模式1:传了 userId,精确重置 ===== - // 验证用户是否存在且手机号匹配 User user = userService.getByUserId(param.getUserId()); if (user == null) { return fail("用户不存在"); } - if (!param.getPhone().equals(user.getPhone())) { - return fail("手机号与账号不匹配"); + if (byEmail) { + if (!param.getEmail().equals(user.getEmail())) { + return fail("邮箱与账号不匹配"); + } + } else { + if (!param.getPhone().equals(user.getPhone())) { + return fail("手机号与账号不匹配"); + } } if (param.getTenantId() != null && !param.getTenantId().equals(user.getTenantId())) { @@ -1574,18 +1604,14 @@ public class MainController extends BaseController { boolean success = userService.resetUserPassword(param.getUserId(), user.getTenantId(), param.getNewPassword()); if (success) { - // 密码重置成功后删除验证码 - redisUtil.delete(key); - - // 记录登录日志(密码重置) + redisUtil.delete(verifyKey); LoginRecord record = new LoginRecord(); record.setUsername(user.getUsername()); record.setNickname(user.getNickname()); - record.setLoginType(5); // 5表示密码重置(需要在LoginRecord中定义常量) + record.setLoginType(5); record.setComments("密码重置成功"); record.setTenantId(user.getTenantId()); loginRecordService.save(record); - return success("密码重置成功"); } else { return fail("密码重置失败,请稍后重试"); diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml index 5bc690a..b16b724 100644 --- a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml @@ -384,15 +384,20 @@ diff --git a/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java b/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java index 7811f89..918997a 100644 --- a/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java +++ b/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java @@ -21,14 +21,18 @@ import java.io.Serializable; public class ResetPasswordParam implements Serializable { private static final long serialVersionUID = 1L; - @NotBlank(message = "手机号不能为空") - @Schema(description = "手机号码", required = true) + @Schema(description = "手机号码(手机找回时必填)") private String phone; - @NotBlank(message = "短信验证码不能为空") - @Schema(description = "短信验证码", required = true) + @Schema(description = "短信验证码(手机找回时必填)") private String smsCode; + @Schema(description = "邮箱(邮箱找回时必填)") + private String email; + + @Schema(description = "邮箱验证码(邮箱找回时必填)") + private String emailCode; + @Schema(description = "用户ID(未登录忘记密码场景可不传,后端按手机号查用户)") private String userId;