feat(auth): 优化密码修改和重置逻辑

- 修改自己密码时新增多种输入校验,区分未设置密码用户免旧密码验证
- 重置密码接口支持两种模式:精确指定账号和通过手机号批量重置
- 忘记密码场景下手机号查询所有正常账号统一重置密码,排除冻结账号
- 精确定义用户和租户校验逻辑,确保数据匹配且安全
- 重置密码成功后,删除短信验证码缓存并记录登录日志
- 调整ResetPasswordParam参数注释,userId和tenantId支持非必填以适应场景
- User实体增加hasPassword字段,标记用户是否已设置密码
- UserServiceImpl中设置hasPassword字段以支持业务逻辑判断
This commit is contained in:
2026-07-24 19:22:48 +08:00
parent 34c6076068
commit 73f0878fb2
4 changed files with 66 additions and 12 deletions

View File

@@ -535,16 +535,26 @@ public class MainController extends BaseController {
@Operation(summary = "修改自己密码") @Operation(summary = "修改自己密码")
@PutMapping("/auth/password") @PutMapping("/auth/password")
public ApiResult<?> updatePassword(@RequestBody UpdatePasswordParam param) { public ApiResult<?> updatePassword(@RequestBody UpdatePasswordParam param) {
if (StrUtil.hasBlank(param.getOldPassword(), param.getPassword())) { if (StrUtil.isBlank(param.getPassword())) {
return fail("参数不能为空"); return fail("新密码不能为空");
} }
Integer userId = getLoginUserId(); Integer userId = getLoginUserId();
if (userId == null) { if (userId == null) {
return fail("未登录"); return fail("未登录");
} }
if (!userService.comparePassword(userService.getById(userId).getPassword(), param.getOldPassword())) { User dbUser = userService.getById(userId);
if (dbUser == null) {
return fail("用户不存在");
}
// 已设置过密码的必须验证旧密码;未设置过密码的(如验证码注册用户)直接设置新密码
if (StrUtil.isNotBlank(dbUser.getPassword())) {
if (StrUtil.isBlank(param.getOldPassword())) {
return fail("请输入当前密码");
}
if (!userService.comparePassword(dbUser.getPassword(), param.getOldPassword())) {
return fail("原密码输入不正确"); return fail("原密码输入不正确");
} }
}
User user = new User(); User user = new User();
user.setUserId(userId); user.setUserId(userId);
user.setPassword(userService.encodePassword(param.getPassword())); user.setPassword(userService.encodePassword(param.getPassword()));
@@ -1476,6 +1486,9 @@ public class MainController extends BaseController {
/** /**
* 重置密码(找回密码功能) * 重置密码(找回密码功能)
* 支持两种模式:
* 1. 传 userId + tenantId精确重置指定账号密码
* 2. 不传 userId通过手机号查找所有正常账号统一重置密码忘记密码场景
*/ */
@Operation(summary = "重置密码") @Operation(summary = "重置密码")
@PostMapping("/resetPassword") @PostMapping("/resetPassword")
@@ -1505,6 +1518,45 @@ public class MainController extends BaseController {
return fail("短信验证码不正确"); return fail("短信验证码不正确");
} }
// ===== 模式判断userId 为空时按手机号查所有用户统一重置 =====
if (StrUtil.isBlank(param.getUserId())) {
// 通过手机号查找所有用户(跨租户)
List<User> userList = userService.list(
new LambdaQueryWrapper<User>()
.eq(User::getPhone, param.getPhone())
.eq(User::getDeleted, 0)
);
if (userList.isEmpty()) {
return fail("该手机号未注册");
}
// 过滤掉被冻结的账号
List<User> activeUsers = userList.stream()
.filter(u -> u.getStatus() == null || u.getStatus() == 0)
.collect(Collectors.toList());
if (activeUsers.isEmpty()) {
return fail("账号已被冻结,请联系管理员");
}
// 统一重置所有同手机号的正常账号密码
String encodedPassword = userService.encodePassword(param.getNewPassword());
for (User u : activeUsers) {
User update = new User();
update.setUserId(u.getUserId());
update.setPassword(encodedPassword);
userService.updateById(update);
// 记录登录日志
LoginRecord record = new LoginRecord();
record.setUsername(u.getUsername());
record.setNickname(u.getNickname());
record.setLoginType(5);
record.setComments("密码重置成功(通过手机号)");
record.setTenantId(u.getTenantId());
loginRecordService.save(record);
}
redisUtil.delete(key);
return success("密码重置成功");
}
// ===== 模式1传了 userId精确重置 =====
// 验证用户是否存在且手机号匹配 // 验证用户是否存在且手机号匹配
User user = userService.getByUserId(param.getUserId()); User user = userService.getByUserId(param.getUserId());
if (user == null) { if (user == null) {
@@ -1515,12 +1567,12 @@ public class MainController extends BaseController {
return fail("手机号与账号不匹配"); return fail("手机号与账号不匹配");
} }
if (!param.getTenantId().equals(user.getTenantId())) { if (param.getTenantId() != null && !param.getTenantId().equals(user.getTenantId())) {
return fail("租户信息不匹配"); return fail("租户信息不匹配");
} }
// 重置密码 // 重置密码
boolean success = userService.resetUserPassword(param.getUserId(), param.getTenantId(), param.getNewPassword()); boolean success = userService.resetUserPassword(param.getUserId(), user.getTenantId(), param.getNewPassword());
if (success) { if (success) {
// 密码重置成功后删除验证码 // 密码重置成功后删除验证码

View File

@@ -360,6 +360,10 @@ public class User implements UserDetails {
@TableField(exist = false) @TableField(exist = false)
private Boolean hasAdminsByPhone; private Boolean hasAdminsByPhone;
@Schema(description = "是否已设置密码(未设置过密码的用户可免旧密码直接设置)")
@TableField(exist = false)
private Boolean hasPassword;
@Schema(description = "模板ID") @Schema(description = "模板ID")
private Integer templateId; private Integer templateId;

View File

@@ -29,12 +29,10 @@ public class ResetPasswordParam implements Serializable {
@Schema(description = "短信验证码", required = true) @Schema(description = "短信验证码", required = true)
private String smsCode; private String smsCode;
@NotBlank(message = "用户ID不能为空") @Schema(description = "用户ID(未登录忘记密码场景可不传,后端按手机号查用户)")
@Schema(description = "用户ID", required = true)
private String userId; private String userId;
@NotNull(message = "租户ID不能为空") @Schema(description = "租户ID(未登录忘记密码场景可不传)")
@Schema(description = "租户ID", required = true)
private Integer tenantId; private Integer tenantId;
@NotBlank(message = "新密码不能为空") @NotBlank(message = "新密码不能为空")
@@ -47,7 +45,6 @@ public class ResetPasswordParam implements Serializable {
@Schema(description = "确认密码", required = true) @Schema(description = "确认密码", required = true)
private String confirmPassword; private String confirmPassword;
@NotNull(message = "模板ID不能为空") @Schema(description = "短信模板ID(可选)")
@Schema(description = "短信模板ID", required = true)
private Integer templateId; private Integer templateId;
} }

View File

@@ -89,6 +89,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
param.setUserId(userId); param.setUserId(userId);
User user = param.getOne(baseMapper.selectListRel(param)); User user = param.getOne(baseMapper.selectListRel(param));
if (user != null) { if (user != null) {
user.setHasPassword(StrUtil.isNotBlank(user.getPassword()));
user.setPassword(null); user.setPassword(null);
user.setRoles(userRoleService.listByUserId(user.getUserId())); user.setRoles(userRoleService.listByUserId(user.getUserId()));
user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null));