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