mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	Merge branch 'jskils-fix-last-commit' into dev
This commit is contained in:
		| @@ -99,10 +99,24 @@ public class LoginUser implements Serializable { | |||||||
|      */ |      */ | ||||||
|     private LocalDateTime loginTime; |     private LocalDateTime loginTime; | ||||||
|  |  | ||||||
|     public LoginUser(Set<String> permissions, Set<String> roleCodes, Set<RoleDTO> roles) { |     /** | ||||||
|  |      * 最后一次修改密码时间 | ||||||
|  |      */ | ||||||
|  |     private LocalDateTime pwdResetTime; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 登录时系统设置的密码过期天数 | ||||||
|  |      */ | ||||||
|  |     private Integer passwordExpirationDays; | ||||||
|  |  | ||||||
|  |     public LoginUser(Set<String> permissions, | ||||||
|  |                      Set<String> roleCodes, | ||||||
|  |                      Set<RoleDTO> roles, | ||||||
|  |                      Integer passwordExpirationDays) { | ||||||
|         this.permissions = permissions; |         this.permissions = permissions; | ||||||
|         this.roleCodes = roleCodes; |         this.roleCodes = roleCodes; | ||||||
|         this.roles = roles; |         this.roles = roles; | ||||||
|  |         this.passwordExpirationDays = passwordExpirationDays; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -116,4 +130,21 @@ public class LoginUser implements Serializable { | |||||||
|         } |         } | ||||||
|         return roleCodes.contains(SysConstants.ADMIN_ROLE_CODE); |         return roleCodes.contains(SysConstants.ADMIN_ROLE_CODE); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 密码是否已过期 | ||||||
|  |      * | ||||||
|  |      * @return 是否过期 | ||||||
|  |      */ | ||||||
|  |     public boolean isPasswordExpired() { | ||||||
|  |         // 永久有效 | ||||||
|  |         if (this.passwordExpirationDays == null || this.passwordExpirationDays <= SysConstants.NO) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // 初始密码(第三方登录用户)暂不提示修改 | ||||||
|  |         if (this.pwdResetTime == null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return this.pwdResetTime.plusDays(this.passwordExpirationDays).isBefore(LocalDateTime.now()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package top.continew.admin.auth.config.satoken; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 密码配置属性 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2024/6/15 22:15 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @Component | ||||||
|  | @ConfigurationProperties(prefix = "auth.password") | ||||||
|  | public class LoginPasswordProperties { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 排除(放行)路径配置 | ||||||
|  |      */ | ||||||
|  |     private String[] excludes = new String[0]; | ||||||
|  | } | ||||||
| @@ -16,9 +16,17 @@ | |||||||
|  |  | ||||||
| package top.continew.admin.auth.config.satoken; | package top.continew.admin.auth.config.satoken; | ||||||
|  |  | ||||||
|  | import cn.dev33.satoken.interceptor.SaInterceptor; | ||||||
|  | import cn.dev33.satoken.router.SaRouter; | ||||||
| import cn.dev33.satoken.stp.StpInterface; | import cn.dev33.satoken.stp.StpInterface; | ||||||
|  | import lombok.RequiredArgsConstructor; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
|  | import top.continew.admin.common.model.dto.LoginUser; | ||||||
|  | import top.continew.admin.common.util.helper.LoginHelper; | ||||||
|  | import top.continew.starter.auth.satoken.autoconfigure.SaTokenExtensionProperties; | ||||||
|  | import top.continew.starter.core.constant.StringConstants; | ||||||
|  | import top.continew.starter.core.util.validate.CheckUtils; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Sa-Token 配置 |  * Sa-Token 配置 | ||||||
| @@ -27,8 +35,12 @@ import org.springframework.context.annotation.Configuration; | |||||||
|  * @since 2022/12/19 22:13 |  * @since 2022/12/19 22:13 | ||||||
|  */ |  */ | ||||||
| @Configuration | @Configuration | ||||||
|  | @RequiredArgsConstructor | ||||||
| public class SaTokenConfiguration { | public class SaTokenConfiguration { | ||||||
|  |  | ||||||
|  |     private final SaTokenExtensionProperties properties; | ||||||
|  |     private final LoginPasswordProperties loginPasswordProperties; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Sa-Token 权限认证配置 |      * Sa-Token 权限认证配置 | ||||||
|      */ |      */ | ||||||
| @@ -36,4 +48,20 @@ public class SaTokenConfiguration { | |||||||
|     public StpInterface stpInterface() { |     public StpInterface stpInterface() { | ||||||
|         return new SaTokenPermissionImpl(); |         return new SaTokenPermissionImpl(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * SaToken 拦截器配置 | ||||||
|  |      */ | ||||||
|  |     @Bean | ||||||
|  |     public SaInterceptor saInterceptor() { | ||||||
|  |         return new SaInterceptor(handle -> SaRouter.match(StringConstants.PATH_PATTERN) | ||||||
|  |             .notMatch(properties.getSecurity().getExcludes()) | ||||||
|  |             .check(r -> { | ||||||
|  |                 LoginUser loginUser = LoginHelper.getLoginUser(); | ||||||
|  |                 if (SaRouter.isMatchCurrURI(loginPasswordProperties.getExcludes())) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 CheckUtils.throwIf(loginUser.isPasswordExpired(), "密码已过期,请修改密码"); | ||||||
|  |             })); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -68,6 +68,8 @@ import java.time.LocalDateTime; | |||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
|  |  | ||||||
|  | import static top.continew.admin.system.enums.PasswordPolicyEnum.PASSWORD_EXPIRATION_DAYS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 登录业务实现 |  * 登录业务实现 | ||||||
|  * |  * | ||||||
| @@ -209,8 +211,11 @@ public class LoginServiceImpl implements LoginService { | |||||||
|             .listRoleCodeByUserId(userId), threadPoolTaskExecutor); |             .listRoleCodeByUserId(userId), threadPoolTaskExecutor); | ||||||
|         CompletableFuture<Set<RoleDTO>> roleFuture = CompletableFuture.supplyAsync(() -> roleService |         CompletableFuture<Set<RoleDTO>> roleFuture = CompletableFuture.supplyAsync(() -> roleService | ||||||
|             .listByUserId(userId), threadPoolTaskExecutor); |             .listByUserId(userId), threadPoolTaskExecutor); | ||||||
|  |         CompletableFuture<Integer> passwordExpirationDaysFuture = CompletableFuture.supplyAsync(() -> optionService | ||||||
|  |             .getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); | ||||||
|         CompletableFuture.allOf(permissionFuture, roleCodeFuture, roleFuture); |         CompletableFuture.allOf(permissionFuture, roleCodeFuture, roleFuture); | ||||||
|         LoginUser loginUser = new LoginUser(permissionFuture.join(), roleCodeFuture.join(), roleFuture.join()); |         LoginUser loginUser = new LoginUser(permissionFuture.join(), roleCodeFuture.join(), roleFuture | ||||||
|  |             .join(), passwordExpirationDaysFuture.join()); | ||||||
|         BeanUtil.copyProperties(user, loginUser); |         BeanUtil.copyProperties(user, loginUser); | ||||||
|         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 | ||||||
|   | |||||||
| @@ -128,7 +128,7 @@ public class AuthController { | |||||||
|         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(loginUser.isPasswordExpired()); | ||||||
|         return R.ok(userInfoResp); |         return R.ok(userInfoResp); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -190,6 +190,16 @@ cosid: | |||||||
|         machine-bit: 3 |         machine-bit: 3 | ||||||
|         sequence-bit: 9 |         sequence-bit: 9 | ||||||
|  |  | ||||||
|  | --- ### 认证配置 | ||||||
|  | auth: | ||||||
|  |   ## 密码配置 | ||||||
|  |   password: | ||||||
|  |     excludes: | ||||||
|  |       - /auth/route | ||||||
|  |       - /auth/user/info | ||||||
|  |       - /auth/logout | ||||||
|  |       - /system/user/password | ||||||
|  |  | ||||||
| --- ### 服务器配置 | --- ### 服务器配置 | ||||||
| server: | server: | ||||||
|   servlet: |   servlet: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user