feat(auth): 优化密码修改和重置逻辑
- 修改自己密码时新增多种输入校验,区分未设置密码用户免旧密码验证 - 重置密码接口支持两种模式:精确指定账号和通过手机号批量重置 - 忘记密码场景下手机号查询所有正常账号统一重置密码,排除冻结账号 - 精确定义用户和租户校验逻辑,确保数据匹配且安全 - 重置密码成功后,删除短信验证码缓存并记录登录日志 - 调整ResetPasswordParam参数注释,userId和tenantId支持非必填以适应场景 - User实体增加hasPassword字段,标记用户是否已设置密码 - UserServiceImpl中设置hasPassword字段以支持业务逻辑判断
This commit is contained in:
@@ -535,16 +535,26 @@ public class MainController extends BaseController {
|
||||
@Operation(summary = "修改自己密码")
|
||||
@PutMapping("/auth/password")
|
||||
public ApiResult<?> updatePassword(@RequestBody UpdatePasswordParam param) {
|
||||
if (StrUtil.hasBlank(param.getOldPassword(), param.getPassword())) {
|
||||
return fail("参数不能为空");
|
||||
if (StrUtil.isBlank(param.getPassword())) {
|
||||
return fail("新密码不能为空");
|
||||
}
|
||||
Integer userId = getLoginUserId();
|
||||
if (userId == null) {
|
||||
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("原密码输入不正确");
|
||||
}
|
||||
}
|
||||
User user = new User();
|
||||
user.setUserId(userId);
|
||||
user.setPassword(userService.encodePassword(param.getPassword()));
|
||||
@@ -1476,6 +1486,9 @@ public class MainController extends BaseController {
|
||||
|
||||
/**
|
||||
* 重置密码(找回密码功能)
|
||||
* 支持两种模式:
|
||||
* 1. 传 userId + tenantId:精确重置指定账号密码
|
||||
* 2. 不传 userId:通过手机号查找所有正常账号,统一重置密码(忘记密码场景)
|
||||
*/
|
||||
@Operation(summary = "重置密码")
|
||||
@PostMapping("/resetPassword")
|
||||
@@ -1505,6 +1518,45 @@ public class MainController extends BaseController {
|
||||
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());
|
||||
if (user == null) {
|
||||
@@ -1515,12 +1567,12 @@ public class MainController extends BaseController {
|
||||
return fail("手机号与账号不匹配");
|
||||
}
|
||||
|
||||
if (!param.getTenantId().equals(user.getTenantId())) {
|
||||
if (param.getTenantId() != null && !param.getTenantId().equals(user.getTenantId())) {
|
||||
return fail("租户信息不匹配");
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
boolean success = userService.resetUserPassword(param.getUserId(), param.getTenantId(), param.getNewPassword());
|
||||
boolean success = userService.resetUserPassword(param.getUserId(), user.getTenantId(), param.getNewPassword());
|
||||
|
||||
if (success) {
|
||||
// 密码重置成功后删除验证码
|
||||
|
||||
@@ -360,6 +360,10 @@ public class User implements UserDetails {
|
||||
@TableField(exist = false)
|
||||
private Boolean hasAdminsByPhone;
|
||||
|
||||
@Schema(description = "是否已设置密码(未设置过密码的用户可免旧密码直接设置)")
|
||||
@TableField(exist = false)
|
||||
private Boolean hasPassword;
|
||||
|
||||
@Schema(description = "模板ID")
|
||||
private Integer templateId;
|
||||
|
||||
|
||||
@@ -29,12 +29,10 @@ public class ResetPasswordParam implements Serializable {
|
||||
@Schema(description = "短信验证码", required = true)
|
||||
private String smsCode;
|
||||
|
||||
@NotBlank(message = "用户ID不能为空")
|
||||
@Schema(description = "用户ID", required = true)
|
||||
@Schema(description = "用户ID(未登录忘记密码场景可不传,后端按手机号查用户)")
|
||||
private String userId;
|
||||
|
||||
@NotNull(message = "租户ID不能为空")
|
||||
@Schema(description = "租户ID", required = true)
|
||||
@Schema(description = "租户ID(未登录忘记密码场景可不传)")
|
||||
private Integer tenantId;
|
||||
|
||||
@NotBlank(message = "新密码不能为空")
|
||||
@@ -47,7 +45,6 @@ public class ResetPasswordParam implements Serializable {
|
||||
@Schema(description = "确认密码", required = true)
|
||||
private String confirmPassword;
|
||||
|
||||
@NotNull(message = "模板ID不能为空")
|
||||
@Schema(description = "短信模板ID", required = true)
|
||||
@Schema(description = "短信模板ID(可选)")
|
||||
private Integer templateId;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
param.setUserId(userId);
|
||||
User user = param.getOne(baseMapper.selectListRel(param));
|
||||
if (user != null) {
|
||||
user.setHasPassword(StrUtil.isNotBlank(user.getPassword()));
|
||||
user.setPassword(null);
|
||||
user.setRoles(userRoleService.listByUserId(user.getUserId()));
|
||||
user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null));
|
||||
|
||||
Reference in New Issue
Block a user