From e8ee5ad6918f7e2912329926be5c963221a26643 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子li <15040126243@163.com>
Date: 星期四, 02 十二月 2021 16:04:45 +0800
Subject: [PATCH] update 用户登录 支持校验错误次数锁定登录
---
ruoyi-admin/src/main/resources/i18n/messages_en_US.properties | 8 ++--
ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java | 28 ++++++++++++-
ruoyi-admin/src/main/resources/i18n/messages.properties | 8 ++--
ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java | 8 ++-
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java | 15 +++++++
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java | 8 ++--
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java | 2
ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties | 8 ++--
8 files changed, 62 insertions(+), 23 deletions(-)
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
index ede2df8..6db4b42 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -2,12 +2,12 @@
not.null=* 蹇呴』濉啓
user.jcaptcha.error=楠岃瘉鐮侀敊璇�
user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥
-user.not.exists=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.not.exists=瀵逛笉璧�, 鎮ㄧ殑璐﹀彿锛歿0} 涓嶅瓨鍦�.
user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆�
-user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾10鍒嗛挓
-user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿宸茶鍒犻櫎
-user.blocked=鐢ㄦ埛宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+user.password.retry.limit.exceed=瀵嗙爜閿欒娆℃暟杩囧锛屽笎鎴烽攣瀹歿0}鍒嗛挓
+user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茶鍒犻櫎
+user.blocked=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茬鐢紝璇疯仈绯荤鐞嗗憳
role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
user.logout.success=閫�鍑烘垚鍔�
length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
index af57cf4..c67beab 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -2,12 +2,12 @@
not.null=* Required fill in
user.jcaptcha.error=Captcha error
user.jcaptcha.expire=Captcha invalid
-user.not.exists=User does not exist/Password error
+user.not.exists=Sorry, your account: {0} does not exist
user.password.not.match=User does not exist/Password error
user.password.retry.limit.count=Password input error {0} times
-user.password.retry.limit.exceed=Password input error {0} times, account locked for 10 minutes
-user.password.delete=Sorry, your account has been deleted
-user.blocked=User disabled锛宲lease contact administrators
+user.password.retry.limit.exceed=Too many password errors, account locked for {0} minutes
+user.password.delete=Sorry, your account锛歿0} has been deleted
+user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
role.blocked=Role disabled锛宲lease contact administrators
user.logout.success=Exit successful
length.not.valid=The length must be between {min} and {max} characters
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
index ede2df8..6db4b42 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -2,12 +2,12 @@
not.null=* 蹇呴』濉啓
user.jcaptcha.error=楠岃瘉鐮侀敊璇�
user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥
-user.not.exists=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.not.exists=瀵逛笉璧�, 鎮ㄧ殑璐﹀彿锛歿0} 涓嶅瓨鍦�.
user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆�
-user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾10鍒嗛挓
-user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿宸茶鍒犻櫎
-user.blocked=鐢ㄦ埛宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+user.password.retry.limit.exceed=瀵嗙爜閿欒娆℃暟杩囧锛屽笎鎴烽攣瀹歿0}鍒嗛挓
+user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茶鍒犻櫎
+user.blocked=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茬鐢紝璇疯仈绯荤鐞嗗憳
role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
user.logout.success=閫�鍑烘垚鍔�
length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index 0c5a92c..76e959d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -84,6 +84,21 @@
Integer CAPTCHA_EXPIRATION = 2;
/**
+ * 鐧婚檰閿欒 redis key
+ */
+ String LOGIN_ERROR = "login_error:";
+
+ /**
+ * 鐧诲綍閿欒娆℃暟
+ */
+ Integer LOGIN_ERROR_NUMBER = 5;
+
+ /**
+ * 鐧诲綍閿欒闄愬埗鏃堕棿(鍒嗛挓)
+ */
+ Integer LOGIN_ERROR_LIMIT_TIME = 10;
+
+ /**
* 浠ょ墝
*/
String TOKEN = "token";
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
index 94dbcdd..99a8880 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
@@ -10,7 +10,7 @@
public class UserException extends BaseException {
private static final long serialVersionUID = 1L;
- public UserException(String code, Object[] args) {
+ public UserException(String code, Object... args) {
super("user", code, args, null);
}
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
index 857cbe3..76d8090 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
@@ -7,6 +7,7 @@
import com.ruoyi.common.core.service.LogininforService;
import com.ruoyi.common.core.service.TokenService;
import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -40,14 +41,15 @@
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
LoginUser loginUser = tokenService.getLoginUser(request);
- if (StringUtils.isNotNull(loginUser)) {
+ String message = MessageUtils.message("user.logout.success");
+ if (StringUtils.isNotNull(loginUser)) {
String userName = loginUser.getUsername();
// 鍒犻櫎鐢ㄦ埛缂撳瓨璁板綍
tokenService.delLoginUser(loginUser.getToken());
// 璁板綍鐢ㄦ埛閫�鍑烘棩蹇�
- asyncService.recordLogininfor(userName, Constants.LOGOUT, "閫�鍑烘垚鍔�", request);
+ asyncService.recordLogininfor(userName, Constants.LOGOUT, message, request);
}
- ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(HttpStatus.HTTP_OK, "閫�鍑烘垚鍔�")));
+ ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(HttpStatus.HTTP_OK, message)));
}
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
index 70f6601..6add556 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service;
+import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
@@ -8,7 +9,7 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
-import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
+import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.RedisUtils;
@@ -22,6 +23,7 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
+import java.util.concurrent.TimeUnit;
/**
* 鐧诲綍鏍¢獙鏂规硶
@@ -62,6 +64,13 @@
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);
+ }
// 鐢ㄦ埛楠岃瘉
Authentication authentication = null;
try {
@@ -70,13 +79,26 @@
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
- asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"), request);
- throw new UserPasswordNotMatchException();
+ // 鏄惁绗竴娆�
+ 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);
+ }
} else {
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage(), request);
throw new ServiceException(e.getMessage());
}
}
+ // 鐧诲綍鎴愬姛 娓呯┖閿欒娆℃暟
+ RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId(), username);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java
index 14801e9..8472d68 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java
@@ -3,7 +3,7 @@
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserStatus;
-import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysPermissionService;
@@ -34,13 +34,13 @@
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user)) {
log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
- throw new ServiceException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
+ throw new UserException("user.not.exists", username);
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍒犻櫎.", username);
- throw new ServiceException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸茶鍒犻櫎");
+ throw new UserException("user.password.delete", username);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
- throw new ServiceException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸插仠鐢�");
+ throw new UserException("user.blocked", username);
}
return createLoginUser(user);
--
Gitblit v1.9.3