mirror of https://gitee.com/stylefeng/roses
【8.0】【auth】【login】登录改造,增加租户参数传递逻辑
parent
17dc0a105c
commit
cc0fed9d92
|
@ -0,0 +1,21 @@
|
|||
package cn.stylefeng.roses.kernel.auth.api;
|
||||
|
||||
/**
|
||||
* 租户编码的接口,通过租户编码获取到租户ID
|
||||
* <p>
|
||||
* 一般用在登录接口,通过租户的编码获取租户的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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
* <p>
|
||||
* 开源版不提供租户管理的功能,只能提供单租户编码的维护,也就是默认租户
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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<LoginUser> loginUserCache, CacheOperatorApi<Set<String>> allPlaceLoginTokenCache) {
|
||||
public SessionManagerApi sessionManagerApi(CacheOperatorApi<LoginUser> loginUserCache,
|
||||
CacheOperatorApi<Set<String>> 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<LoginUser> loginUserCache, CacheOperatorApi<Set<String>> allPlaceLoginTokenCache) {
|
||||
public ClearInvalidLoginUserCacheTimer clearInvalidLoginUserCacheTimer(CacheOperatorApi<LoginUser> loginUserCache,
|
||||
CacheOperatorApi<Set<String>> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ public class TenantRemoveThreadLocalHolder implements RemoveThreadLocalApi {
|
|||
@Override
|
||||
public void removeThreadLocalAction() {
|
||||
TenantIdHolder.remove();
|
||||
TenantSwitchHolder.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Boolean> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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和最后登录时间
|
||||
|
|
|
@ -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<SysUserMapper, SysUser> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserValidateDTO getUserLoginValidateDTO(String account) {
|
||||
public UserValidateDTO getUserLoginValidateDTO(Long tenantId, String account) {
|
||||
LambdaQueryWrapper<SysUser> 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<SysUser> 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);
|
||||
|
|
Loading…
Reference in New Issue