Files
xgy-oa/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
KonBAI 8c029a3dc3 !10 sync 同步ruoyi-vue-plus更新
update sa-token 1.28.0 => 1.29.0
修复Xss注解字段值为空时的异常问题
删除方法无返回值时,方法注释上的@HTTP4O4
update 使用 satoken 自带的 BCrypt 工具 替换 Security 加密工具 减少依赖
优化流程任务方法,统一响应格式
fix 修复 R 参数位置错误
fix 修复 验证码 强制校验问题
update 返回体 统一
修复自定义组件file-upload无法显示第一个文件,列表显示的文件比实际文件少一个的问题
update 修改验证码校验 增加 uuid 空判断
update 优化代码生成
fix 修复因升级 sa-token 导致 doLogin 无法获取 token 问题
update 更新 swagger 配置类错误注释
update 优化 TreeBuildUtils 工具 使用反射自动获取顶级父id
fix 回滚代码生成部分优化 修复优化导致的问题
update 使用 hutool Dict 优化 JsonUtils 防止类型解析异常
update 优化代码生成 使用新 JsonUtils.parseMap 方法
2022-02-15 14:20:20 +00:00

168 lines
7.1 KiB
Java

package com.ruoyi.system.service;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.dto.RoleDTO;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.service.LogininforService;
import com.ruoyi.common.enums.DeviceType;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 登录校验方法
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class SysLoginService {
private final ISysUserService userService;
private final ISysConfigService configService;
private final LogininforService asyncService;
private final SysPermissionService permissionService;
/**
* 登录验证
*
* @param username 用户名
* @param password 密码
* @param code 验证码
* @param uuid 唯一标识
* @return 结果
*/
public String login(String username, String password, String code, String uuid) {
HttpServletRequest request = ServletUtils.getRequest();
boolean captchaOnOff = configService.selectCaptchaOnOff();
// 验证码开关
if (captchaOnOff) {
validateCaptcha(username, code, uuid, request);
}
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + username);
// 锁定时间内登录 则踢出
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
}
SysUser user = loadUserByUsername(username);
if (!BCrypt.checkpw(password, user.getPassword())) {
// 是否第一次
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
// 达到规定错误次数 则锁定登录
if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
} else {
// 未达到规定错误次数 则递增
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber);
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", errorNumber), request);
throw new UserException("user.password.retry.limit.count", errorNumber);
}
}
// 登录成功 清空错误次数
RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
recordLoginInfo(user.getUserId(), username);
LoginUser loginUser = buildLoginUser(user);
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.PC);
return StpUtil.getTokenValue();
}
/**
* 校验验证码
*
* @param username 用户名
* @param code 验证码
* @param uuid 唯一标识
*/
public void validateCaptcha(String username, String code, String uuid, HttpServletRequest request) {
String verifyKey = Constants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey);
if (captcha == null) {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"), request);
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha)) {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"), request);
throw new CaptchaException();
}
}
private SysUser loadUserByUsername(String username) {
SysUser user = userService.selectUserByUserName(username);
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", username);
throw new UserException("user.password.delete", username);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
return user;
}
/**
* 构建登录用户
*/
private LoginUser buildLoginUser(SysUser user) {
LoginUser loginUser = new LoginUser();
loginUser.setUserId(user.getUserId());
loginUser.setDeptId(user.getDeptId());
loginUser.setUsername(user.getUserName());
loginUser.setNickName(user.getNickName());
loginUser.setUserType(user.getUserType());
loginUser.setMenuPermission(permissionService.getMenuPermission(user));
loginUser.setRolePermission(permissionService.getRolePermission(user));
loginUser.setDeptName(user.getDept().getDeptName());
List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class);
loginUser.setRoles(roles);
return loginUser;
}
/**
* 记录登录信息
*
* @param userId 用户ID
*/
public void recordLoginInfo(Long userId, String username) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(ServletUtils.getClientIP());
sysUser.setLoginDate(DateUtils.getNowDate());
sysUser.setUpdateBy(username);
userService.updateUserProfile(sysUser);
}
}