ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java
@@ -8,13 +8,9 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.enums.UserStatus; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.RemoteLogService; import com.ruoyi.system.api.RemoteUserService; import com.ruoyi.system.api.domain.SysLogininfor; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; @@ -27,10 +23,13 @@ public class SysLoginService { @Autowired private RemoteLogService remoteLogService; private RemoteUserService remoteUserService; @Autowired private RemoteUserService remoteUserService; private SysPasswordService passwordService; @Autowired private SysRecordLogService recordLogService; /** * 登录 @@ -40,21 +39,21 @@ // 用户名或密码为空 错误 if (StringUtils.isAnyBlank(username, password)) { recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); throw new ServiceException("用户/密码必须填写"); } // 密码如果不在指定范围内 错误 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"); throw new ServiceException("用户密码不在指定范围"); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) { recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); throw new ServiceException("用户名不在指定范围"); } // 查询用户信息 @@ -67,33 +66,29 @@ if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) { recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); throw new ServiceException("登录用户:" + username + " 不存在"); } LoginUser userInfo = userResult.getData(); SysUser user = userResult.getData().getSysUser(); if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } if (!SecurityUtils.matchesPassword(password, user.getPassword())) { recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码错误"); throw new ServiceException("用户不存在/密码错误"); } recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); passwordService.validate(user, password); recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); return userInfo; } public void logout(String loginName) { recordLogininfor(loginName, Constants.LOGOUT, "退出成功"); recordLogService.recordLogininfor(loginName, Constants.LOGOUT, "退出成功"); } /** @@ -128,32 +123,6 @@ { throw new ServiceException(registerResult.getMsg()); } recordLogininfor(username, Constants.REGISTER, "注册成功"); recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功"); } /** * 记录登录信息 * * @param username 用户名 * @param status 状态 * @param message 消息内容 * @return */ public void recordLogininfor(String username, String status, String message) { SysLogininfor logininfor = new SysLogininfor(); logininfor.setUserName(username); logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest())); logininfor.setMsg(message); // 日志状态 if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS); } else if (Constants.LOGIN_FAIL.equals(status)) { logininfor.setStatus(Constants.LOGIN_FAIL_STATUS); } remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER); } } } ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysPasswordService.java
New file @@ -0,0 +1,85 @@ package com.ruoyi.auth.service; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysUser; /** * 登录密码方法 * * @author ruoyi */ @Component public class SysPasswordService { @Autowired private RedisService redisService; private int maxRetryCount = CacheConstants.passwordMaxRetryCount; private Long lockTime = CacheConstants.passwordLockTime; @Autowired private SysRecordLogService recordLogService; /** * 登录账户密码错误次数缓存键名 * * @param username 用户名 * @return 缓存键key */ private String getCacheKey(String username) { return CacheConstants.PWD_ERR_CNT_KEY + username; } public void validate(SysUser user, String password) { String username = user.getUserName(); Integer retryCount = redisService.getCacheObject(getCacheKey(username)); if (retryCount == null) { retryCount = 0; } if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) { String errMsg = String.format("密码输入错误%s次,帐户锁定%s分钟", maxRetryCount, lockTime); recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL,errMsg); throw new ServiceException(errMsg); } if (!matches(user, password)) { retryCount = retryCount + 1; recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, String.format("密码输入错误%s次", maxRetryCount)); redisService.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES); throw new ServiceException("用户不存在/密码错误"); } else { clearLoginRecordCache(username); } } public boolean matches(SysUser user, String rawPassword) { return SecurityUtils.matchesPassword(rawPassword, user.getPassword()); } public void clearLoginRecordCache(String loginName) { if (redisService.hasKey(getCacheKey(loginName))) { redisService.deleteObject(getCacheKey(loginName)); } } } ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysRecordLogService.java
New file @@ -0,0 +1,49 @@ package com.ruoyi.auth.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.system.api.RemoteLogService; import com.ruoyi.system.api.domain.SysLogininfor; /** * 记录日志方法 * * @author ruoyi */ @Component public class SysRecordLogService { @Autowired private RemoteLogService remoteLogService; /** * 记录登录信息 * * @param username 用户名 * @param status 状态 * @param message 消息内容 * @return */ public void recordLogininfor(String username, String status, String message) { SysLogininfor logininfor = new SysLogininfor(); logininfor.setUserName(username); logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest())); logininfor.setMsg(message); // 日志状态 if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS); } else if (Constants.LOGIN_FAIL.equals(status)) { logininfor.setStatus(Constants.LOGIN_FAIL_STATUS); } remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER); } } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
@@ -1,7 +1,7 @@ package com.ruoyi.common.core.constant; /** * 缓存的key 常量 * 缓存常量信息 * * @author ruoyi */ @@ -18,7 +18,37 @@ public final static long REFRESH_TIME = 120; /** * 密码最大错误次数 */ public final static int passwordMaxRetryCount = 5; /** * 密码锁定时间,默认10(分钟) */ public final static long passwordLockTime = 10; /** * 权限缓存前缀 */ public final static String LOGIN_TOKEN_KEY = "login_tokens:"; /** * 验证码 redis key */ public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; /** * 参数管理 cache key */ public static final String SYS_CONFIG_KEY = "sys_config:"; /** * 字典管理 cache key */ public static final String SYS_DICT_KEY = "sys_dict:"; /** * 登录账户密码错误次数 redis key */ public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
@@ -103,25 +103,9 @@ public static final String IS_ASC = "isAsc"; /** * 验证码 redis key */ public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; /** * 验证码有效期(分钟) */ public static final long CAPTCHA_EXPIRATION = 2; /** * 参数管理 cache key */ public static final String SYS_CONFIG_KEY = "sys_config:"; /** * 字典管理 cache key */ public static final String SYS_DICT_KEY = "sys_dict:"; /** * 资源映射路径 前缀 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
@@ -1,6 +1,7 @@ package com.ruoyi.common.core.web.domain; import java.util.HashMap; import java.util.Objects; import com.ruoyi.common.core.constant.HttpStatus; import com.ruoyi.common.core.utils.StringUtils; @@ -56,20 +57,6 @@ { super.put(DATA_TAG, data); } } /** * 方便链式调用 * * @param key * @param value * @return */ @Override public AjaxResult put(String key, Object value) { super.put(key, value); return this; } /** @@ -159,4 +146,38 @@ { return new AjaxResult(code, msg, null); } /** * 是否为成功消息 * * @return 结果 */ public boolean isSuccess() { return !isError(); } /** * 是否为错误消息 * * @return 结果 */ public boolean isError() { return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG)); } /** * 方便链式调用 * * @param key * @param value * @return */ @Override public AjaxResult put(String key, Object value) { super.put(key, value); return this; } } ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java
@@ -3,7 +3,7 @@ import java.util.Collection; import java.util.List; import com.alibaba.fastjson2.JSONArray; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.redis.service.RedisService; @@ -58,7 +58,7 @@ */ public static void clearDictCache() { Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(Constants.SYS_DICT_KEY + "*"); Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.SYS_DICT_KEY + "*"); SpringUtils.getBean(RedisService.class).deleteObject(keys); } @@ -70,6 +70,6 @@ */ public static String getCacheKey(String configKey) { return Constants.SYS_DICT_KEY + configKey; return CacheConstants.SYS_DICT_KEY + configKey; } } ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java
@@ -9,6 +9,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.FastByteArrayOutputStream; import com.google.code.kaptcha.Producer; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.exception.CaptchaException; import com.ruoyi.common.core.utils.StringUtils; @@ -55,7 +56,7 @@ // 保存验证码信息 String uuid = IdUtils.simpleUUID(); String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; String capStr = null, code = null; BufferedImage image = null; @@ -106,7 +107,7 @@ { throw new CaptchaException("验证码已失效"); } String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; String captcha = redisService.getCacheObject(verifyKey); redisService.deleteObject(verifyKey); ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -5,7 +5,7 @@ import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.text.Convert; @@ -162,7 +162,7 @@ @Override public void clearConfigCache() { Collection<String> keys = redisService.keys(Constants.SYS_CONFIG_KEY + "*"); Collection<String> keys = redisService.keys(CacheConstants.SYS_CONFIG_KEY + "*"); redisService.deleteObject(keys); } @@ -202,6 +202,6 @@ */ private String getCacheKey(String configKey) { return Constants.SYS_CONFIG_KEY + configKey; return CacheConstants.SYS_CONFIG_KEY + configKey; } }