mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	feat: 禁止密码过期用户访问业务接口
This commit is contained in:
		| @@ -97,6 +97,16 @@ public class LoginUser implements Serializable { | |||||||
|      */ |      */ | ||||||
|     private LocalDateTime loginTime; |     private LocalDateTime loginTime; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 最后一次修改密码时间 | ||||||
|  |      */ | ||||||
|  |     private LocalDateTime pwdResetTime; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 登录时系统设置的密码过期天数 | ||||||
|  |      */ | ||||||
|  |     private Integer passwordExpirationDays; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 是否为管理员 |      * 是否为管理员 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -25,9 +25,11 @@ import cn.hutool.extra.servlet.JakartaServletUtil; | |||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import jakarta.servlet.http.HttpServletRequest; | import jakarta.servlet.http.HttpServletRequest; | ||||||
| import top.continew.admin.common.constant.CacheConstants; | import top.continew.admin.common.constant.CacheConstants; | ||||||
|  | import top.continew.admin.common.constant.SysConstants; | ||||||
| import top.continew.admin.common.model.dto.LoginUser; | import top.continew.admin.common.model.dto.LoginUser; | ||||||
| import top.continew.starter.core.util.ExceptionUtils; | import top.continew.starter.core.util.ExceptionUtils; | ||||||
| import top.continew.starter.core.util.IpUtils; | import top.continew.starter.core.util.IpUtils; | ||||||
|  | import top.continew.starter.core.util.validate.CheckUtils; | ||||||
| import top.continew.starter.extension.crud.service.CommonUserService; | import top.continew.starter.extension.crud.service.CommonUserService; | ||||||
| import top.continew.starter.web.util.ServletUtils; | import top.continew.starter.web.util.ServletUtils; | ||||||
|  |  | ||||||
| @@ -75,6 +77,16 @@ public class LoginHelper { | |||||||
|      * @throws NotLoginException 未登录异常 |      * @throws NotLoginException 未登录异常 | ||||||
|      */ |      */ | ||||||
|     public static LoginUser getLoginUser() throws NotLoginException { |     public static LoginUser getLoginUser() throws NotLoginException { | ||||||
|  |         return getLoginUser(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 登录用户信息 | ||||||
|  |      * | ||||||
|  |      * @param checkPasswordExpired 是否校验密码过期 | ||||||
|  |      * @throws NotLoginException 未登录异常 | ||||||
|  |      */ | ||||||
|  |     public static LoginUser getLoginUser(boolean checkPasswordExpired) throws NotLoginException { | ||||||
|         StpUtil.checkLogin(); |         StpUtil.checkLogin(); | ||||||
|         LoginUser loginUser = (LoginUser)SaHolder.getStorage().get(CacheConstants.LOGIN_USER_KEY); |         LoginUser loginUser = (LoginUser)SaHolder.getStorage().get(CacheConstants.LOGIN_USER_KEY); | ||||||
|         if (null != loginUser) { |         if (null != loginUser) { | ||||||
| @@ -83,9 +95,33 @@ public class LoginHelper { | |||||||
|         SaSession tokenSession = StpUtil.getTokenSession(); |         SaSession tokenSession = StpUtil.getTokenSession(); | ||||||
|         loginUser = (LoginUser)tokenSession.get(CacheConstants.LOGIN_USER_KEY); |         loginUser = (LoginUser)tokenSession.get(CacheConstants.LOGIN_USER_KEY); | ||||||
|         SaHolder.getStorage().set(CacheConstants.LOGIN_USER_KEY, loginUser); |         SaHolder.getStorage().set(CacheConstants.LOGIN_USER_KEY, loginUser); | ||||||
|  |         CheckUtils.throwIf(checkPasswordExpired && isPasswordExpired(loginUser), "密码已过期,请立即修改。"); | ||||||
|         return loginUser; |         return loginUser; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 密码是否已过期 | ||||||
|  |      * | ||||||
|  |      * @param loginUser 登录用户 | ||||||
|  |      * @return 是否过期 | ||||||
|  |      */ | ||||||
|  |     public static boolean isPasswordExpired(LoginUser loginUser) { | ||||||
|  |         if (loginUser == null) { | ||||||
|  |             loginUser = getLoginUser(); | ||||||
|  |         } | ||||||
|  |         LocalDateTime pwdResetTime = loginUser.getPwdResetTime(); | ||||||
|  |         Integer passwordExpirationDays = loginUser.getPasswordExpirationDays(); | ||||||
|  |         // 永久有效 | ||||||
|  |         if (passwordExpirationDays == null || passwordExpirationDays <= SysConstants.NO) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // 初始密码也提示修改 | ||||||
|  |         if (pwdResetTime == null) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return pwdResetTime.plusDays(passwordExpirationDays).isBefore(LocalDateTime.now()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 根据 Token 获取登录用户信息 |      * 根据 Token 获取登录用户信息 | ||||||
|      * |      * | ||||||
| @@ -109,6 +145,16 @@ public class LoginHelper { | |||||||
|         return getLoginUser().getId(); |         return getLoginUser().getId(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取登录用户 ID | ||||||
|  |      * | ||||||
|  |      * @param checkPasswordExpired 是否校验密码过期 | ||||||
|  |      * @return 登录用户 ID | ||||||
|  |      */ | ||||||
|  |     public static Long getUserId(boolean checkPasswordExpired) { | ||||||
|  |         return getLoginUser(checkPasswordExpired).getId(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取登录用户名 |      * 获取登录用户名 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -61,6 +61,8 @@ import java.time.Duration; | |||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.util.*; | import java.util.*; | ||||||
|  |  | ||||||
|  | import static top.continew.admin.system.enums.PasswordPolicyEnum.PASSWORD_EXPIRATION_DAYS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 登录业务实现 |  * 登录业务实现 | ||||||
|  * |  * | ||||||
| @@ -199,6 +201,7 @@ public class LoginServiceImpl implements LoginService { | |||||||
|         loginUser.setPermissions(permissionService.listPermissionByUserId(userId)); |         loginUser.setPermissions(permissionService.listPermissionByUserId(userId)); | ||||||
|         loginUser.setRoleCodes(permissionService.listRoleCodeByUserId(userId)); |         loginUser.setRoleCodes(permissionService.listRoleCodeByUserId(userId)); | ||||||
|         loginUser.setRoles(roleService.listByUserId(userId)); |         loginUser.setRoles(roleService.listByUserId(userId)); | ||||||
|  |         loginUser.setPasswordExpirationDays(optionService.getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); | ||||||
|         return LoginHelper.login(loginUser); |         return LoginHelper.login(loginUser); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ import top.continew.starter.data.mybatis.plus.service.IService; | |||||||
| import top.continew.starter.extension.crud.service.BaseService; | import top.continew.starter.extension.crud.service.BaseService; | ||||||
|  |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.time.LocalDateTime; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -90,14 +89,6 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ | |||||||
|      */ |      */ | ||||||
|     void updatePassword(String oldPassword, String newPassword, Long id); |     void updatePassword(String oldPassword, String newPassword, Long id); | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 密码是否已过期 |  | ||||||
|      * |  | ||||||
|      * @param pwdResetTime 上次重置密码时间 |  | ||||||
|      * @return 是否过期 |  | ||||||
|      */ |  | ||||||
|     boolean isPasswordExpired(LocalDateTime pwdResetTime); |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 修改手机号 |      * 修改手机号 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
|  |  | ||||||
| package top.continew.admin.system.service.impl; | package top.continew.admin.system.service.impl; | ||||||
|  |  | ||||||
|  | import cn.dev33.satoken.stp.StpUtil; | ||||||
| import cn.hutool.core.bean.BeanUtil; | import cn.hutool.core.bean.BeanUtil; | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.img.ImgUtil; | import cn.hutool.core.img.ImgUtil; | ||||||
| @@ -210,20 +211,8 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|         baseMapper.updateById(user); |         baseMapper.updateById(user); | ||||||
|         // 保存历史密码 |         // 保存历史密码 | ||||||
|         userPasswordHistoryService.add(id, password, passwordRepetitionTimes); |         userPasswordHistoryService.add(id, password, passwordRepetitionTimes); | ||||||
|     } |         // 修改后登出 | ||||||
|  |         StpUtil.logout(); | ||||||
|     @Override |  | ||||||
|     public boolean isPasswordExpired(LocalDateTime pwdResetTime) { |  | ||||||
|         // 永久有效 |  | ||||||
|         int passwordExpirationDays = optionService.getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name()); |  | ||||||
|         if (passwordExpirationDays <= SysConstants.NO) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         // 初始密码也提示修改 |  | ||||||
|         if (pwdResetTime == null) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         return pwdResetTime.plusDays(passwordExpirationDays).isBefore(LocalDateTime.now()); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -123,12 +123,12 @@ public class AuthController { | |||||||
|     @Operation(summary = "获取用户信息", description = "获取登录用户信息") |     @Operation(summary = "获取用户信息", description = "获取登录用户信息") | ||||||
|     @GetMapping("/user/info") |     @GetMapping("/user/info") | ||||||
|     public R<UserInfoResp> getUserInfo() { |     public R<UserInfoResp> getUserInfo() { | ||||||
|         LoginUser loginUser = LoginHelper.getLoginUser(); |         LoginUser loginUser = LoginHelper.getLoginUser(false); | ||||||
|         UserDetailResp userDetailResp = userService.get(loginUser.getId()); |         UserDetailResp userDetailResp = userService.get(loginUser.getId()); | ||||||
|         UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class); |         UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class); | ||||||
|         userInfoResp.setPermissions(loginUser.getPermissions()); |         userInfoResp.setPermissions(loginUser.getPermissions()); | ||||||
|         userInfoResp.setRoles(loginUser.getRoleCodes()); |         userInfoResp.setRoles(loginUser.getRoleCodes()); | ||||||
|         userInfoResp.setPwdExpired(userService.isPasswordExpired(userDetailResp.getPwdResetTime())); |         userInfoResp.setPwdExpired(LoginHelper.isPasswordExpired(loginUser)); | ||||||
|         return R.ok(userInfoResp); |         return R.ok(userInfoResp); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -136,6 +136,6 @@ public class AuthController { | |||||||
|     @Operation(summary = "获取路由信息", description = "获取登录用户的路由信息") |     @Operation(summary = "获取路由信息", description = "获取登录用户的路由信息") | ||||||
|     @GetMapping("/route") |     @GetMapping("/route") | ||||||
|     public R<List<RouteResp>> listRoute() { |     public R<List<RouteResp>> listRoute() { | ||||||
|         return R.ok(loginService.buildRouteTree(LoginHelper.getUserId())); |         return R.ok(loginService.buildRouteTree(LoginHelper.getUserId(false))); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -94,7 +94,7 @@ public class UserCenterController { | |||||||
|         String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq |         String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq | ||||||
|             .getNewPassword())); |             .getNewPassword())); | ||||||
|         ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败"); |         ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败"); | ||||||
|         userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId()); |         userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId(false)); | ||||||
|         return R.ok("修改成功,请牢记你的新密码"); |         return R.ok("修改成功,请牢记你的新密码"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 kils
					kils