fix(auth): 增加 JWT 安全版本号与 TokenManager.invalidateUserSessions,统一角色与密码变更的按用户下线行为

Closes #ID8B31
This commit is contained in:
Ray.Hao
2025-12-02 17:34:36 +08:00
parent 6e8769ccb7
commit 289f79cdb4
9 changed files with 132 additions and 57 deletions

View File

@@ -195,24 +195,24 @@ public class UserController {
return Result.judge(result);
}
@Operation(summary = "重置用户密码")
@Operation(summary = "重置指定用户密码")
@PutMapping(value = "/{userId}/password/reset")
@PreAuthorize("@ss.hasPerm('sys:user:reset-password')")
public Result<?> resetPassword(
public Result<?> resetUserPassword(
@Parameter(description = "用户ID") @PathVariable Long userId,
@RequestParam String password
) {
boolean result = userService.resetPassword(userId, password);
boolean result = userService.resetUserPassword(userId, password);
return Result.judge(result);
}
@Operation(summary = "修改密码")
@Operation(summary = "当前用户修改密码")
@PutMapping(value = "/password")
public Result<?> changePassword(
public Result<?> changeCurrentUserPassword(
@RequestBody PasswordUpdateForm data
) {
Long currUserId = SecurityUtils.getUserId();
boolean result = userService.changePassword(currUserId, data);
boolean result = userService.changeUserPassword(currUserId, data);
return Result.judge(result);
}

View File

@@ -107,22 +107,22 @@ public interface UserService extends IService<User> {
boolean updateUserProfile(UserProfileForm formData);
/**
* 修改用户密码
* 修改指定用户密码
*
* @param userId 用户ID
* @param data 修改密码表单数据
* @return {@link Boolean} 是否修改成功
*/
boolean changePassword(Long userId, PasswordUpdateForm data);
boolean changeUserPassword(Long userId, PasswordUpdateForm data);
/**
* 重置用户密码
* 重置指定用户密码
*
* @param userId 用户ID
* @param password 重置后的密码
* @return {@link Boolean} 是否重置成功
*/
boolean resetPassword(Long userId, String password);
boolean resetUserPassword(Long userId, String password);
/**
* 发送短信验证码(绑定或更换手机号)

View File

@@ -72,11 +72,9 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
.in(UserRole::getRoleId, removedRoles));
}
// 当权限变更时清除登录态
// 当权限变更时清除被修改用户的登录态
if (rolesChanged) {
// 获取用户所有有效token根据实际token存储实现
String accessToken = SecurityUtils.getTokenFromRequest();
tokenManager.invalidateToken(accessToken);
tokenManager.invalidateUserSessions(userId);
}
}

View File

@@ -485,14 +485,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
}
/**
* 修改用户密码
* 修改指定用户密码
*
* @param userId 用户ID
* @param data 密码修改表单数据
* @return true|false
*/
@Override
public boolean changePassword(Long userId, PasswordUpdateForm data) {
public boolean changeUserPassword(Long userId, PasswordUpdateForm data) {
User user = this.getById(userId);
if (user == null) {
@@ -522,26 +522,30 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
);
if (result) {
// 加入黑名单,重新登录
String accessToken = SecurityUtils.getTokenFromRequest();
tokenManager.invalidateToken(accessToken);
// 密码变更后,使当前用户的所有会话失效,强制重新登录
tokenManager.invalidateUserSessions(userId);
}
return result;
}
/**
* 重置密码
* 重置指定用户密码
*
* @param userId 用户ID
* @param password 密码重置表单数据
* @return true|false
*/
@Override
public boolean resetPassword(Long userId, String password) {
return this.update(new LambdaUpdateWrapper<User>()
public boolean resetUserPassword(Long userId, String password) {
boolean result = this.update(new LambdaUpdateWrapper<User>()
.eq(User::getId, userId)
.set(User::getPassword, passwordEncoder.encode(password))
);
if (result) {
// 管理员重置用户密码后,使该用户的所有会话失效
tokenManager.invalidateUserSessions(userId);
}
return result;
}
/**