sql/ry_20230221.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/common/exception/user/BlackListException.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/common/utils/ip/IpUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/framework/aspectj/LogAspect.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/framework/security/service/SysLoginService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/ruoyi/framework/security/service/TokenService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/resources/i18n/messages.properties | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
sql/ry_20230221.sql
ÎļþÃû´Ó sql/ry_20230216.sql ÐÞ¸Ä @@ -545,6 +545,7 @@ insert into sys_config values(3, 'ä¸»æ¡æ¶é¡µ-ä¾§è¾¹æ 主é¢', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, 'æ·±è²ä¸»é¢theme-darkï¼æµ è²ä¸»é¢theme-light' ); insert into sys_config values(4, 'è´¦å·èªå©-éªè¯ç å¼å ³', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, 'æ¯å¦å¼å¯éªè¯ç åè½ï¼trueå¼å¯ï¼falseå ³éï¼'); insert into sys_config values(5, 'è´¦å·èªå©-æ¯å¦å¼å¯ç¨æ·æ³¨ååè½', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, 'æ¯å¦å¼å¯æ³¨åç¨æ·åè½ï¼trueå¼å¯ï¼falseå ³éï¼'); insert into sys_config values(6, 'ç¨æ·ç»å½-é»ååå表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置ç»å½IPé»ååéå¶ï¼å¤ä¸ªå¹é 项以;åéï¼æ¯æå¹é ï¼*éé ãç½æ®µï¼'); -- ---------------------------- src/main/java/com/ruoyi/common/exception/user/BlackListException.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.common.exception.user; /** * é»ååIPå¼å¸¸ç±» * * @author ruoyi */ public class BlackListException extends UserException { private static final long serialVersionUID = 1L; public BlackListException() { super("login.blocked", null); } } src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.common.exception.user; /** * ç¨æ·ä¸åå¨å¼å¸¸ç±» * * @author ruoyi */ public class UserNotExistsException extends UserException { private static final long serialVersionUID = 1L; public UserNotExistsException() { super("user.not.exists", null); } } src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
@@ -3,6 +3,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import javax.servlet.http.HttpServletRequest; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.StringUtils; /** @@ -12,6 +13,23 @@ */ public class IpUtils { public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; // å¹é ip public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")"; public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))"; // å¹é ç½æ®µ public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")"; /** * è·å客æ·ç«¯IP * * @return IPå°å */ public static String getIpAddr() { return getIpAddr(ServletUtils.getRequest()); } /** * è·å客æ·ç«¯IP * @@ -248,7 +266,7 @@ } } } return ip; return StringUtils.substring(ip, 0, 255); } /** @@ -261,4 +279,104 @@ { return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); } /** * æ¯å¦ä¸ºIP */ public static boolean isIP(String ip) { return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP); } /** * æ¯å¦ä¸ºIPï¼æ *为é´éçéé 符å°å */ public static boolean isIpWildCard(String ip) { return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD); } /** * æ£æµåæ°æ¯å¦å¨ipéé 符é */ public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip) { String[] s1 = ipWildCard.split("\\."); String[] s2 = ip.split("\\."); boolean isMatchedSeg = true; for (int i = 0; i < s1.length && !s1[i].equals("*"); i++) { if (!s1[i].equals(s2[i])) { isMatchedSeg = false; break; } } return isMatchedSeg; } /** * æ¯å¦ä¸ºç¹å®æ ¼å¼å¦:â10.10.10.1-10.10.10.99âçip段å符串 */ public static boolean isIPSegment(String ipSeg) { return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG); } /** * 夿ipæ¯å¦å¨æå®ç½æ®µä¸ */ public static boolean ipIsInNetNoCheck(String iparea, String ip) { int idx = iparea.indexOf('-'); String[] sips = iparea.substring(0, idx).split("\\."); String[] sipe = iparea.substring(idx + 1).split("\\."); String[] sipt = ip.split("\\."); long ips = 0L, ipe = 0L, ipt = 0L; for (int i = 0; i < 4; ++i) { ips = ips << 8 | Integer.parseInt(sips[i]); ipe = ipe << 8 | Integer.parseInt(sipe[i]); ipt = ipt << 8 | Integer.parseInt(sipt[i]); } if (ips > ipe) { long t = ips; ips = ipe; ipe = t; } return ips <= ipt && ipt <= ipe; } /** * æ ¡éªipæ¯å¦ç¬¦åè¿æ»¤ä¸²è§å * * @param filter è¿æ»¤IPå表,æ¯æåç¼'*'éé ,æ¯æç½æ®µå¦:`10.10.10.1-10.10.10.99` * @param ip æ ¡éªIPå°å * @return boolean ç»æ */ public static boolean isMatchedIp(String filter, String ip) { if (StringUtils.isEmpty(filter) && StringUtils.isEmpty(ip)) { return false; } String[] ips = filter.split(";"); for (String iStr : ips) { if (isIP(iStr) && iStr.equals(ip)) { return true; } else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) { return true; } else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) { return true; } } return false; } } src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
@@ -90,7 +90,7 @@ SysOperLog operLog = new SysOperLog(); operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); // 请æ±çå°å String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr(); operLog.setOperIp(ip); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); if (loginUser != null) src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -14,7 +14,6 @@ import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.framework.aspectj.lang.annotation.RateLimiter; @@ -79,7 +78,7 @@ StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); if (rateLimiter.limitType() == LimitType.IP) { stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-"); stringBuffer.append(IpUtils.getIpAddr()).append("-"); } MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
@@ -38,7 +38,7 @@ final Object... args) { final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); final String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); final String ip = IpUtils.getIpAddr(); return new TimerTask() { @Override src/main/java/com/ruoyi/framework/security/service/SysLoginService.java
@@ -9,13 +9,15 @@ import org.springframework.stereotype.Component; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.user.BlackListException; import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.CaptchaExpireException; import com.ruoyi.common.exception.user.UserNotExistsException; import com.ruoyi.common.exception.user.UserPasswordNotMatchException; 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.ip.IpUtils; import com.ruoyi.framework.manager.AsyncManager; @@ -46,7 +48,7 @@ @Autowired private ISysUserService userService; @Autowired private ISysConfigService configService; @@ -61,12 +63,10 @@ */ public String login(String username, String password, String code, String uuid) { boolean captchaEnabled = configService.selectCaptchaEnabled(); // éªè¯ç å¼å ³ if (captchaEnabled) { validateCaptcha(username, code, uuid); } // éªè¯ç æ ¡éª validateCaptcha(username, code, uuid); // ç»å½åç½®æ ¡éª loginPreCheck(username, password); // ç¨æ·éªè¯ Authentication authentication = null; try @@ -110,18 +110,58 @@ */ public void validateCaptcha(String username, String code, String uuid) { String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); String captcha = redisCache.getCacheObject(verifyKey); redisCache.deleteObject(verifyKey); if (captcha == null) boolean captchaEnabled = configService.selectCaptchaEnabled(); if (captchaEnabled) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); throw new CaptchaExpireException(); String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); String captcha = redisCache.getCacheObject(verifyKey); redisCache.deleteObject(verifyKey); if (captcha == null) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); throw new CaptchaExpireException(); } if (!code.equalsIgnoreCase(captcha)) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); throw new CaptchaException(); } } if (!code.equalsIgnoreCase(captcha)) } /** * ç»å½åç½®æ ¡éª * @param username ç¨æ·å * @param password ç¨æ·å¯ç */ public void loginPreCheck(String username, String password) { // ç¨æ·åæå¯ç 为空 é误 if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); throw new CaptchaException(); AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); throw new UserNotExistsException(); } // å¯ç 妿ä¸å¨æå®èå´å é误 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); throw new UserPasswordNotMatchException(); } // ç¨æ·åä¸å¨æå®èå´å é误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); throw new UserPasswordNotMatchException(); } // IPé»ååæ ¡éª String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); throw new BlackListException(); } } @@ -134,7 +174,7 @@ { SysUser sysUser = new SysUser(); sysUser.setUserId(userId); sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest())); sysUser.setLoginIp(IpUtils.getIpAddr()); sysUser.setLoginDate(DateUtils.getNowDate()); userService.updateUserProfile(sysUser); } src/main/java/com/ruoyi/framework/security/service/TokenService.java
@@ -156,7 +156,7 @@ public void setUserAgent(LoginUser loginUser) { UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr(); loginUser.setIpaddr(ip); loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); loginUser.setBrowser(userAgent.getBrowser().getName()); src/main/resources/i18n/messages.properties
@@ -9,6 +9,7 @@ user.password.delete=对ä¸èµ·ï¼æ¨çè´¦å·å·²è¢«å é¤ user.blocked=ç¨æ·å·²å°ç¦ï¼è¯·è系管çå role.blocked=è§è²å·²å°ç¦ï¼è¯·è系管çå login.blocked=å¾éæ¾ï¼è®¿é®IP已被åå ¥ç³»ç»é»åå user.logout.success=éåºæå length.not.valid=é¿åº¦å¿ é¡»å¨{min}å°{max}个å符ä¹é´