diff --git a/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/TenantCodeGetApi.java b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/TenantCodeGetApi.java new file mode 100644 index 000000000..38910f297 --- /dev/null +++ b/kernel-d-auth/auth-api/src/main/java/cn/stylefeng/roses/kernel/auth/api/TenantCodeGetApi.java @@ -0,0 +1,21 @@ +package cn.stylefeng.roses.kernel.auth.api; + +/** + * 租户编码的接口,通过租户编码获取到租户ID + *

+ * 一般用在登录接口,通过租户的编码获取租户的id信息 + * + * @author fengshuonan + * @since 2023/8/31 23:49 + */ +public interface TenantCodeGetApi { + + /** + * 通过租户编码获取租户的ID + * + * @author fengshuonan + * @since 2023/8/31 23:50 + */ + Long getTenantIdByCode(String tenantCode); + +} diff --git a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java index cf11f0ab6..292bdb11b 100644 --- a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java +++ b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/AuthServiceImpl.java @@ -238,12 +238,12 @@ public class AuthServiceImpl implements AuthServiceApi { public LoginUser createNewLoginInfo(String token, DefaultJwtPayload defaultJwtPayload) { // 获取用户的信息 - String account = defaultJwtPayload.getAccount(); + Long userId = defaultJwtPayload.getUserId(); LoginUser loginUser; // 获取用户信息 - UserValidateDTO userValidateDTO = sysUserServiceApi.getUserLoginValidateDTO(account); + UserValidateDTO userValidateDTO = sysUserServiceApi.getUserLoginValidateDTO(userId); // 创建登录用户 loginUser = new LoginUser(userValidateDTO.getUserId(), token); diff --git a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/DefaultTenantCodeProvider.java b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/DefaultTenantCodeProvider.java new file mode 100644 index 000000000..14d576f0b --- /dev/null +++ b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/DefaultTenantCodeProvider.java @@ -0,0 +1,34 @@ +package cn.stylefeng.roses.kernel.auth.auth; + +import cn.stylefeng.roses.kernel.auth.api.TenantCodeGetApi; +import cn.stylefeng.roses.kernel.sys.api.expander.TenantConfigExpander; +import lombok.extern.slf4j.Slf4j; + +/** + * 获取默认的租户id + *

+ * 开源版不提供租户管理的功能,只能提供单租户编码的维护,也就是默认租户 + * + * @author fengshuonan + * @since 2023/9/1 0:38 + */ +@Slf4j +public class DefaultTenantCodeProvider implements TenantCodeGetApi { + + /** + * 一个不存在的租户id + */ + public static final Long DEFAULT_NONE_TENANT_ID = -999L; + + @Override + public Long getTenantIdByCode(String tenantCode) { + Long defaultRootTenantId = TenantConfigExpander.getDefaultRootTenantId(); + if (defaultRootTenantId.toString().equals(tenantCode)) { + return defaultRootTenantId; + } else { + log.warn("当前系统为单租户系统,不支持多租户功能!"); + return DEFAULT_NONE_TENANT_ID; + } + } + +} diff --git a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java index f533b1ae6..25eb426b7 100644 --- a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java +++ b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java @@ -8,6 +8,7 @@ import cn.hutool.http.HttpResponse; import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi; import cn.stylefeng.roses.kernel.auth.api.SsoServerApi; import cn.stylefeng.roses.kernel.auth.api.TempSecretApi; +import cn.stylefeng.roses.kernel.auth.api.TenantCodeGetApi; import cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants; import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants; import cn.stylefeng.roses.kernel.auth.api.context.AuthJwtContext; @@ -80,6 +81,9 @@ public class LoginService { @Resource private PasswordStoredEncryptApi passwordStoredEncryptApi; + @Resource + private TenantCodeGetApi tenantCodeGetApi; + /** * 登录的真正业务逻辑 * @@ -125,13 +129,12 @@ public class LoginService { } } - // 4.1 通过租户编码获取租户id,如果租户参数没传,则默认填充根租户的id todo + // 4.1 通过租户编码获取租户id,如果租户参数没传,则默认填充根租户的id String tenantCode = loginRequest.getTenantCode(); - - + Long tenantId = tenantCodeGetApi.getTenantIdByCode(tenantCode); // 5. 获取用户密码的加密值和用户的状态 - UserValidateDTO userValidateInfo = sysUserServiceApi.getUserLoginValidateDTO(loginRequest.getAccount()); + UserValidateDTO userValidateInfo = sysUserServiceApi.getUserLoginValidateDTO(tenantId, loginRequest.getAccount()); // 6. 校验用户密码是否正确 validateUserPassword(validatePassword, loginErrorCount, loginRequest, userValidateInfo); diff --git a/kernel-d-auth/auth-spring-boot-starter/src/main/java/cn/stylefeng/roses/kernel/auth/starter/AuthAutoConfiguration.java b/kernel-d-auth/auth-spring-boot-starter/src/main/java/cn/stylefeng/roses/kernel/auth/starter/AuthAutoConfiguration.java index 13f6de930..a6e9a1a50 100644 --- a/kernel-d-auth/auth-spring-boot-starter/src/main/java/cn/stylefeng/roses/kernel/auth/starter/AuthAutoConfiguration.java +++ b/kernel-d-auth/auth-spring-boot-starter/src/main/java/cn/stylefeng/roses/kernel/auth/starter/AuthAutoConfiguration.java @@ -25,11 +25,13 @@ package cn.stylefeng.roses.kernel.auth.starter; import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi; +import cn.stylefeng.roses.kernel.auth.api.TenantCodeGetApi; import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander; import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi; import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi; import cn.stylefeng.roses.kernel.auth.api.pojo.auth.PwdRsaSecretProperties; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; +import cn.stylefeng.roses.kernel.auth.auth.DefaultTenantCodeProvider; import cn.stylefeng.roses.kernel.auth.password.BcryptPasswordStoredEncrypt; import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt; import cn.stylefeng.roses.kernel.auth.session.DefaultSessionManager; @@ -111,7 +113,8 @@ public class AuthAutoConfiguration { */ @Bean @ConditionalOnMissingBean(SessionManagerApi.class) - public SessionManagerApi sessionManagerApi(CacheOperatorApi loginUserCache, CacheOperatorApi> allPlaceLoginTokenCache) { + public SessionManagerApi sessionManagerApi(CacheOperatorApi loginUserCache, + CacheOperatorApi> allPlaceLoginTokenCache) { Long sessionExpiredSeconds = AuthConfigExpander.getSessionExpiredSeconds(); return new DefaultSessionManager(loginUserCache, allPlaceLoginTokenCache, sessionExpiredSeconds); } @@ -124,8 +127,21 @@ public class AuthAutoConfiguration { */ @Bean @ConditionalOnMissingBean(ClearInvalidLoginUserCacheTimer.class) - public ClearInvalidLoginUserCacheTimer clearInvalidLoginUserCacheTimer(CacheOperatorApi loginUserCache, CacheOperatorApi> allPlaceLoginTokenCache) { + public ClearInvalidLoginUserCacheTimer clearInvalidLoginUserCacheTimer(CacheOperatorApi loginUserCache, + CacheOperatorApi> allPlaceLoginTokenCache) { return new ClearInvalidLoginUserCacheTimer(loginUserCache, allPlaceLoginTokenCache); } + /** + * 通过租户编码获取租户id的查询接口 + * + * @author fengshuonan + * @since 2023/9/1 0:52 + */ + @Bean + @ConditionalOnMissingBean(TenantCodeGetApi.class) + public TenantCodeGetApi tenantCodeGetApi() { + return new DefaultTenantCodeProvider(); + } + } diff --git a/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/ProjectTenantInterceptor.java b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/ProjectTenantInterceptor.java index e67c33b84..fc6809c3d 100644 --- a/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/ProjectTenantInterceptor.java +++ b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/ProjectTenantInterceptor.java @@ -5,6 +5,7 @@ import cn.stylefeng.roses.kernel.auth.api.context.LoginContext; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; import cn.stylefeng.roses.kernel.db.api.pojo.tenant.TenantTableProperties; import cn.stylefeng.roses.kernel.db.mp.tenant.holder.TenantIdHolder; +import cn.stylefeng.roses.kernel.db.mp.tenant.holder.TenantSwitchHolder; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; @@ -52,6 +53,13 @@ public class ProjectTenantInterceptor implements TenantLineHandler { @Override public boolean ignoreTable(String tableName) { + // 1. 优先从线程变量中获取,这个优先级最高 + Boolean openFlag = TenantSwitchHolder.get(); + if (openFlag != null && !openFlag) { + return true; + } + + // 2. 第2步,从系统配置中获取,是否开启此table的开关 if (tenantTableProperties == null) { return true; } diff --git a/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantRemoveThreadLocalHolder.java b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantRemoveThreadLocalHolder.java index 0d63dd5df..4c9af66e6 100644 --- a/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantRemoveThreadLocalHolder.java +++ b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantRemoveThreadLocalHolder.java @@ -15,6 +15,7 @@ public class TenantRemoveThreadLocalHolder implements RemoveThreadLocalApi { @Override public void removeThreadLocalAction() { TenantIdHolder.remove(); + TenantSwitchHolder.remove(); } } diff --git a/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantSwitchHolder.java b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantSwitchHolder.java new file mode 100644 index 000000000..19542e737 --- /dev/null +++ b/kernel-d-db/db-sdk-mp/src/main/java/cn/stylefeng/roses/kernel/db/mp/tenant/holder/TenantSwitchHolder.java @@ -0,0 +1,43 @@ +package cn.stylefeng.roses.kernel.db.mp.tenant.holder; + +/** + * 是否开启租户过滤的开关,此优先级最高 + * + * @author fengshuonan + * @since 2023/9/1 0:09 + */ +public class TenantSwitchHolder { + + private static final ThreadLocal TENANT_SWITCH_FLAG_HOLDER = new ThreadLocal<>(); + + /** + * 设置是否开启租户过滤,true开启,false关闭 + * + * @author fengshuonan + * @since 2023/9/1 0:11 + */ + public static void set(Boolean tenantSwitch) { + TENANT_SWITCH_FLAG_HOLDER.set(tenantSwitch); + } + + /** + * 获取租户开启开关 + * + * @author fengshuonan + * @since 2023/9/1 0:11 + */ + public static Boolean get() { + return TENANT_SWITCH_FLAG_HOLDER.get(); + } + + /** + * 清空开关 + * + * @author fengshuonan + * @since 2023/9/1 0:11 + */ + public static void remove() { + TENANT_SWITCH_FLAG_HOLDER.remove(); + } + +} diff --git a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java index 27548c919..92ff15cb9 100644 --- a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java +++ b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/sys/api/SysUserServiceApi.java @@ -58,11 +58,21 @@ public interface SysUserServiceApi { /** * 获取用于用户校验的 * - * @param account 用户账号 + * @param tenantId 指定租户id + * @param account 用户账号 * @author fengshuonan * @since 2023/6/17 21:56 */ - UserValidateDTO getUserLoginValidateDTO(String account); + UserValidateDTO getUserLoginValidateDTO(Long tenantId, String account); + + /** + * 通过用户id创建用户的校验信息 + * + * @param userId 用户id + * @author fengshuonan + * @since 2023/6/17 21:56 + */ + UserValidateDTO getUserLoginValidateDTO(Long userId); /** * 更新用户的登录ip和最后登录时间 diff --git a/kernel-s-system/system-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java b/kernel-s-system/system-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java index b2d1976c6..4fcb068ca 100644 --- a/kernel-s-system/system-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java +++ b/kernel-s-system/system-business-hr/src/main/java/cn/stylefeng/roses/kernel/sys/modular/user/service/impl/SysUserServiceImpl.java @@ -12,6 +12,8 @@ import cn.stylefeng.roses.kernel.db.api.factory.PageFactory; import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory; import cn.stylefeng.roses.kernel.db.api.pojo.entity.BaseEntity; import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult; +import cn.stylefeng.roses.kernel.db.mp.tenant.holder.TenantIdHolder; +import cn.stylefeng.roses.kernel.db.mp.tenant.holder.TenantSwitchHolder; import cn.stylefeng.roses.kernel.file.api.FileInfoApi; import cn.stylefeng.roses.kernel.file.api.constants.FileConstants; import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum; @@ -359,11 +361,42 @@ public class SysUserServiceImpl extends ServiceImpl impl } @Override - public UserValidateDTO getUserLoginValidateDTO(String account) { + public UserValidateDTO getUserLoginValidateDTO(Long tenantId, String account) { LambdaQueryWrapper sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>(); sysUserLambdaQueryWrapper.eq(SysUser::getAccount, account); sysUserLambdaQueryWrapper.select(SysUser::getPassword, SysUser::getPasswordSalt, SysUser::getStatusFlag, SysUser::getUserId); - SysUser sysUserServiceOne = this.getOne(sysUserLambdaQueryWrapper, false); + + // 单独填充租户id + SysUser sysUserServiceOne; + try { + TenantIdHolder.set(tenantId); + sysUserServiceOne = this.getOne(sysUserLambdaQueryWrapper, false); + } finally { + TenantIdHolder.remove(); + } + + if (sysUserServiceOne == null) { + throw new ServiceException(SysUserExceptionEnum.ACCOUNT_NOT_EXIST); + } + + return new UserValidateDTO(sysUserServiceOne.getUserId(), sysUserServiceOne.getPassword(), sysUserServiceOne.getPasswordSalt(), + sysUserServiceOne.getStatusFlag()); + } + + @Override + public UserValidateDTO getUserLoginValidateDTO(Long userId) { + LambdaQueryWrapper sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>(); + sysUserLambdaQueryWrapper.eq(SysUser::getUserId, userId); + sysUserLambdaQueryWrapper.select(SysUser::getPassword, SysUser::getPasswordSalt, SysUser::getStatusFlag, SysUser::getUserId); + + // 单独填充租户id + SysUser sysUserServiceOne; + try { + TenantSwitchHolder.set(false); + sysUserServiceOne = this.getOne(sysUserLambdaQueryWrapper, false); + } finally { + TenantSwitchHolder.remove(); + } if (sysUserServiceOne == null) { throw new ServiceException(SysUserExceptionEnum.ACCOUNT_NOT_EXIST);