fix 修复 登录错误锁定不区分租户问题

This commit is contained in:
疯狂的狮子Li 2024-08-01 23:20:29 +08:00
parent 588a47897a
commit b886f3a04b
8 changed files with 80 additions and 95 deletions

View File

@ -4,13 +4,14 @@ import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil; 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.lang.Opt;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.lock.annotation.Lock4j; import com.baomidou.lock.annotation.Lock4j;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.TenantConstants; import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
@ -155,16 +156,11 @@ public class SysLoginService {
loginUser.setUserType(user.getUserType()); loginUser.setUserType(user.getUserType());
loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
TenantHelper.dynamic(user.getTenantId(), () -> { Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
SysDeptVo dept = null; loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
if (ObjectUtil.isNotNull(user.getDeptId())) { loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
dept = deptService.selectDeptById(user.getDeptId()); List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
} loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
loginUser.setDeptName(ObjectUtil.isNull(dept) ? "" : dept.getDeptName());
loginUser.setDeptCategory(ObjectUtil.isNull(dept) ? "" : dept.getDeptCategory());
List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
});
return loginUser; return loginUser;
} }
@ -186,7 +182,7 @@ public class SysLoginService {
* 登录校验 * 登录校验
*/ */
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL; String loginFail = Constants.LOGIN_FAIL;
// 获取用户登录错误次数默认为0 (可自定义限制策略 例如: key + username + ip) // 获取用户登录错误次数默认为0 (可自定义限制策略 例如: key + username + ip)

View File

@ -21,7 +21,6 @@ import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
@ -51,13 +50,12 @@ public class EmailAuthStrategy implements IAuthStrategy {
String tenantId = loginBody.getTenantId(); String tenantId = loginBody.getTenantId();
String email = loginBody.getEmail(); String email = loginBody.getEmail();
String emailCode = loginBody.getEmailCode(); String emailCode = loginBody.getEmailCode();
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
// 通过邮箱查找用户 SysUserVo user = loadUserByEmail(email);
SysUserVo user = loadUserByEmail(tenantId, email); loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); return loginService.buildLoginUser(user);
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 });
LoginUser loginUser = loginService.buildLoginUser(user);
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
@ -89,18 +87,16 @@ public class EmailAuthStrategy implements IAuthStrategy {
return code.equals(emailCode); return code.equals(emailCode);
} }
private SysUserVo loadUserByEmail(String tenantId, String email) { private SysUserVo loadUserByEmail(String email) {
return TenantHelper.dynamic(tenantId, () -> { SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email)); if (ObjectUtil.isNull(user)) {
if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", email);
log.info("登录用户:{} 不存在.", email); throw new UserException("user.not.exists", email);
throw new UserException("user.not.exists", email); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", email);
log.info("登录用户:{} 已被停用.", email); throw new UserException("user.blocked", email);
throw new UserException("user.blocked", email); }
} return user;
return user;
});
} }
} }

View File

@ -62,11 +62,12 @@ public class PasswordAuthStrategy implements IAuthStrategy {
if (captchaEnabled) { if (captchaEnabled) {
validateCaptcha(tenantId, username, code, uuid); validateCaptcha(tenantId, username, code, uuid);
} }
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
SysUserVo user = loadUserByUsername(tenantId, username); SysUserVo user = loadUserByUsername(username);
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
// 此处可根据登录用户的数据不同 自行创建 loginUser // 此处可根据登录用户的数据不同 自行创建 loginUser
LoginUser loginUser = loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
@ -107,18 +108,16 @@ public class PasswordAuthStrategy implements IAuthStrategy {
} }
} }
private SysUserVo loadUserByUsername(String tenantId, String username) { private SysUserVo loadUserByUsername(String username) {
return TenantHelper.dynamic(tenantId, () -> { SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username)); if (ObjectUtil.isNull(user)) {
if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", username);
log.info("登录用户:{} 不存在.", username); throw new UserException("user.not.exists", username);
throw new UserException("user.not.exists", username); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", username);
log.info("登录用户:{} 已被停用.", username); throw new UserException("user.blocked", username);
throw new UserException("user.blocked", username); }
} return user;
return user;
});
} }
} }

View File

@ -21,7 +21,6 @@ import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
@ -51,13 +50,12 @@ public class SmsAuthStrategy implements IAuthStrategy {
String tenantId = loginBody.getTenantId(); String tenantId = loginBody.getTenantId();
String phonenumber = loginBody.getPhonenumber(); String phonenumber = loginBody.getPhonenumber();
String smsCode = loginBody.getSmsCode(); String smsCode = loginBody.getSmsCode();
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
// 通过手机号查找用户 SysUserVo user = loadUserByPhonenumber(phonenumber);
SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); return loginService.buildLoginUser(user);
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 });
LoginUser loginUser = loginService.buildLoginUser(user);
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
@ -89,18 +87,16 @@ public class SmsAuthStrategy implements IAuthStrategy {
return code.equals(smsCode); return code.equals(smsCode);
} }
private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { private SysUserVo loadUserByPhonenumber(String phonenumber) {
return TenantHelper.dynamic(tenantId, () -> { SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber)); if (ObjectUtil.isNull(user)) {
if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", phonenumber);
log.info("登录用户:{} 不存在.", phonenumber); throw new UserException("user.not.exists", phonenumber);
throw new UserException("user.not.exists", phonenumber); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", phonenumber);
log.info("登录用户:{} 已被停用.", phonenumber); throw new UserException("user.blocked", phonenumber);
throw new UserException("user.blocked", phonenumber); }
} return user;
return user;
});
} }
} }

View File

@ -92,11 +92,11 @@ public class SocialAuthStrategy implements IAuthStrategy {
} else { } else {
social = list.get(0); social = list.get(0);
} }
// 查找用户 LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> {
SysUserVo user = loadUser(social.getTenantId(), social.getUserId()); SysUserVo user = loadUser(social.getUserId());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 return loginService.buildLoginUser(user);
LoginUser loginUser = loginService.buildLoginUser(user); });
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
@ -116,18 +116,16 @@ public class SocialAuthStrategy implements IAuthStrategy {
return loginVo; return loginVo;
} }
private SysUserVo loadUser(String tenantId, Long userId) { private SysUserVo loadUser(Long userId) {
return TenantHelper.dynamic(tenantId, () -> { SysUserVo user = userMapper.selectVoById(userId);
SysUserVo user = userMapper.selectVoById(userId); if (ObjectUtil.isNull(user)) {
if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", "");
log.info("登录用户:{} 不存在.", ""); throw new UserException("user.not.exists", "");
throw new UserException("user.not.exists", ""); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", "");
log.info("登录用户:{} 已被停用.", ""); throw new UserException("user.blocked", "");
throw new UserException("user.blocked", ""); }
} return user;
return user;
});
} }
} }

View File

@ -22,4 +22,9 @@ public interface CacheConstants {
*/ */
String SYS_DICT_KEY = "sys_dict:"; String SYS_DICT_KEY = "sys_dict:";
/**
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
} }

View File

@ -27,11 +27,6 @@ public interface GlobalConstants {
*/ */
String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
/**
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
/** /**
* 三方认证 redis key * 三方认证 redis key
*/ */

View File

@ -1,7 +1,9 @@
package org.dromara.system.controller.monitor; package org.dromara.system.controller.monitor;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.constant.GlobalConstants; import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
@ -13,8 +15,6 @@ import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysLogininforBo; import org.dromara.system.domain.bo.SysLogininforBo;
import org.dromara.system.domain.vo.SysLogininforVo; import org.dromara.system.domain.vo.SysLogininforVo;
import org.dromara.system.service.ISysLogininforService; import org.dromara.system.service.ISysLogininforService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -79,7 +79,7 @@ public class SysLogininforController extends BaseController {
@Log(title = "账户解锁", businessType = BusinessType.OTHER) @Log(title = "账户解锁", businessType = BusinessType.OTHER)
@GetMapping("/unlock/{userName}") @GetMapping("/unlock/{userName}")
public R<Void> unlock(@PathVariable("userName") String userName) { public R<Void> unlock(@PathVariable("userName") String userName) {
String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName; String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName;
if (RedisUtils.hasKey(loginName)) { if (RedisUtils.hasKey(loginName)) {
RedisUtils.deleteObject(loginName); RedisUtils.deleteObject(loginName);
} }