From 45ac0f23e12ac2a45c6affe9e39d0897e4fad618 Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期四, 16 二月 2023 17:06:10 +0800 Subject: [PATCH] !286 合并 多租户功能 * add 新增 ruoyi-common-tenant 多租户模块 全框架适配多租户改动 * update 优化 隐藏页面主键 * remove 移除 缓存列表功能(多租户缓存功能繁杂多样 没有办法在页面管理) * update 重构 全局缓存KEY 与 常用缓存KEY做区分 * update 重构 OssFactory 加载方式 改为每次比对配置做实例更新 * update 优化 SaTokenDao 改为 Bean 注入 便于扩展 * update 重构 项目初始化数据改为懒加载 不提供热加载 * update 重构 验证码开关使用配置文件(经调查少有动态开启需求) * update 优化 启用 sqlserver 高版本语法 简化sql脚本语法 * update 优化 DataPermissionHelper 增加 开启/关闭 忽略数据权限功能 * update 优化 连接池增加 keepaliveTime 探活参数 * update 优化 调整连接池最长生命周期 防止出现警告 * update 优化 代码生成页面模板 校验不必要的表单数据 * add 新增 StringUtils splitTo 与 splitList 方法 优化业务代码 --- ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java | 115 +++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 78 insertions(+), 37 deletions(-) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java similarity index 63% rename from ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java rename to ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java index 4c298ee..2279512 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.service; +package com.ruoyi.web.service; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.secure.BCrypt; @@ -6,13 +6,14 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.dto.RoleDTO; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.XcxLoginUser; import com.ruoyi.common.core.enums.DeviceType; import com.ruoyi.common.core.enums.LoginType; +import com.ruoyi.common.core.enums.TenantStatus; import com.ruoyi.common.core.enums.UserStatus; import com.ruoyi.common.core.exception.user.CaptchaException; import com.ruoyi.common.core.exception.user.CaptchaExpireException; @@ -21,9 +22,15 @@ import com.ruoyi.common.log.event.LogininforEvent; import com.ruoyi.common.redis.utils.RedisUtils; import com.ruoyi.common.satoken.utils.LoginHelper; +import com.ruoyi.common.tenant.exception.TenantException; +import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.common.web.config.properties.CaptchaProperties; import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.vo.SysTenantVo; import com.ruoyi.system.domain.vo.SysUserVo; import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.service.ISysPermissionService; +import com.ruoyi.system.service.ISysTenantService; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -31,6 +38,7 @@ import org.springframework.stereotype.Service; import java.time.Duration; +import java.util.Date; import java.util.List; import java.util.function.Supplier; @@ -45,8 +53,9 @@ public class SysLoginService { private final SysUserMapper userMapper; - private final ISysConfigService configService; - private final SysPermissionService permissionService; + private final CaptchaProperties captchaProperties; + private final ISysPermissionService permissionService; + private final ISysTenantService tenantService; @Value("${user.password.maxRetryCount}") private Integer maxRetryCount; @@ -63,36 +72,41 @@ * @param uuid 鍞竴鏍囪瘑 * @return 缁撴灉 */ - public String login(String username, String password, String code, String uuid) { + public String login(String tenantId, String username, String password, String code, String uuid) { HttpServletRequest request = ServletUtils.getRequest(); - boolean captchaEnabled = configService.selectCaptchaEnabled(); + boolean captchaEnabled = captchaProperties.getEnable(); // 楠岃瘉鐮佸紑鍏� if (captchaEnabled) { - validateCaptcha(username, code, uuid, request); + validateCaptcha(tenantId, username, code, uuid, request); } - SysUserVo user = loadUserByUsername(username); - checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 鏍¢獙绉熸埛 + checkTenant(tenantId); + + SysUserVo user = loadUserByUsername(tenantId, username); + checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser LoginUser loginUser = buildLoginUser(user); // 鐢熸垚token LoginHelper.loginByDevice(loginUser, DeviceType.PC); - recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); recordLoginInfo(user.getUserId()); return StpUtil.getTokenValue(); } - public String smsLogin(String phonenumber, String smsCode) { + public String smsLogin(String tenantId, String phonenumber, String smsCode) { + // 鏍¢獙绉熸埛 + checkTenant(tenantId); // 閫氳繃鎵嬫満鍙锋煡鎵剧敤鎴� - SysUserVo user = loadUserByPhonenumber(phonenumber); + SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); - checkLogin(LoginType.SMS, user.getUserName(), () -> !validateSmsCode(phonenumber, smsCode)); + checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser LoginUser loginUser = buildLoginUser(user); // 鐢熸垚token LoginHelper.loginByDevice(loginUser, DeviceType.APP); - recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); recordLoginInfo(user.getUserId()); return StpUtil.getTokenValue(); } @@ -104,9 +118,12 @@ // 鏍¢獙 appid + appsrcret + xcxCode 璋冪敤鐧诲綍鍑瘉鏍¢獙鎺ュ彛 鑾峰彇 session_key 涓� openid String openid = ""; SysUserVo user = loadUserByOpenid(openid); + // 鏍¢獙绉熸埛 + checkTenant(user.getTenantId()); // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser XcxLoginUser loginUser = new XcxLoginUser(); + loginUser.setTenantId(user.getTenantId()); loginUser.setUserId(user.getUserId()); loginUser.setUsername(user.getUserName()); loginUser.setUserType(user.getUserType()); @@ -114,7 +131,7 @@ // 鐢熸垚token LoginHelper.loginByDevice(loginUser, DeviceType.XCX); - recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); recordLoginInfo(user.getUserId()); return StpUtil.getTokenValue(); } @@ -126,7 +143,7 @@ try { LoginUser loginUser = LoginHelper.getLoginUser(); StpUtil.logout(); - recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); } catch (NotLoginException ignored) { } } @@ -134,13 +151,15 @@ /** * 璁板綍鐧诲綍淇℃伅 * + * @param tenantId 绉熸埛ID * @param username 鐢ㄦ埛鍚� * @param status 鐘舵�� * @param message 娑堟伅鍐呭 * @return */ - private void recordLogininfor(String username, String status, String message) { + private void recordLogininfor(String tenantId, String username, String status, String message) { LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); logininforEvent.setUsername(username); logininforEvent.setStatus(status); logininforEvent.setMessage(message); @@ -151,10 +170,10 @@ /** * 鏍¢獙鐭俊楠岃瘉鐮� */ - private boolean validateSmsCode(String phonenumber, String smsCode) { - String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + phonenumber); + private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); if (StringUtils.isBlank(code)) { - recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); throw new CaptchaExpireException(); } return code.equals(smsCode); @@ -167,24 +186,25 @@ * @param code 楠岃瘉鐮� * @param uuid 鍞竴鏍囪瘑 */ - public void validateCaptcha(String username, String code, String uuid, HttpServletRequest request) { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + public void validateCaptcha(String tenantId, String username, String code, String uuid, HttpServletRequest request) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); String captcha = RedisUtils.getCacheObject(verifyKey); RedisUtils.deleteObject(verifyKey); if (captcha == null) { - recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); throw new CaptchaExpireException(); } if (!code.equalsIgnoreCase(captcha)) { - recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); throw new CaptchaException(); } } - private SysUserVo loadUserByUsername(String username) { + private SysUserVo loadUserByUsername(String tenantId, String username) { SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() - .select(SysUser::getUserName, SysUser::getStatus) - .eq(SysUser::getUserName, username)); + .select(SysUser::getUserName, SysUser::getStatus) + .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) + .eq(SysUser::getUserName, username)); if (ObjectUtil.isNull(user)) { log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username); throw new UserException("user.not.exists", username); @@ -195,10 +215,11 @@ return userMapper.selectUserByUserName(username); } - private SysUserVo loadUserByPhonenumber(String phonenumber) { + private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() - .select(SysUser::getPhonenumber, SysUser::getStatus) - .eq(SysUser::getPhonenumber, phonenumber)); + .select(SysUser::getPhonenumber, SysUser::getStatus) + .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) + .eq(SysUser::getPhonenumber, phonenumber)); if (ObjectUtil.isNull(user)) { log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber); throw new UserException("user.not.exists", phonenumber); @@ -228,12 +249,13 @@ */ private LoginUser buildLoginUser(SysUserVo user) { LoginUser loginUser = new LoginUser(); + loginUser.setTenantId(user.getTenantId()); loginUser.setUserId(user.getUserId()); loginUser.setDeptId(user.getDeptId()); loginUser.setUsername(user.getUserName()); loginUser.setUserType(user.getUserType()); - loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId(), user.isAdmin())); - loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId(), user.isAdmin())); + loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); + loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); loginUser.setRoles(roles); @@ -257,15 +279,15 @@ /** * 鐧诲綍鏍¢獙 */ - private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) { - String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + private void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { + String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; String loginFail = Constants.LOGIN_FAIL; // 鑾峰彇鐢ㄦ埛鐧诲綍閿欒娆℃暟(鍙嚜瀹氫箟闄愬埗绛栫暐 渚嬪: key + username + ip) Integer errorNumber = RedisUtils.getCacheObject(errorKey); // 閿佸畾鏃堕棿鍐呯櫥褰� 鍒欒涪鍑� if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) { - recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); } @@ -275,12 +297,12 @@ // 杈惧埌瑙勫畾閿欒娆℃暟 鍒欓攣瀹氱櫥褰� if (errorNumber.equals(maxRetryCount)) { RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); - recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); } else { // 鏈揪鍒拌瀹氶敊璇鏁� 鍒欓�掑 RedisUtils.setCacheObject(errorKey, errorNumber); - recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); throw new UserException(loginType.getRetryLimitCount(), errorNumber); } } @@ -288,4 +310,23 @@ // 鐧诲綍鎴愬姛 娓呯┖閿欒娆℃暟 RedisUtils.deleteObject(errorKey); } + + private void checkTenant(String tenantId) { + if (!TenantHelper.isEnable()) { + return; + } + SysTenantVo tenant = tenantService.queryByTenantId(tenantId); + if (ObjectUtil.isNull(tenant)) { + log.info("鐧诲綍绉熸埛锛歿} 涓嶅瓨鍦�.", tenantId); + throw new TenantException("tenant.not.exists"); + } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { + log.info("鐧诲綍绉熸埛锛歿} 宸茶鍋滅敤.", tenantId); + throw new TenantException("tenant.blocked"); + } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) + && new Date().after(tenant.getExpireTime())) { + log.info("鐧诲綍绉熸埛锛歿} 宸茶秴杩囨湁鏁堟湡.", tenantId); + throw new TenantException("tenant.expired"); + } + } + } -- Gitblit v1.9.3