Эх сурвалжийг харах

新增用户名登录免验证码状态

tsurumure 5 сар өмнө
parent
commit
349e04dfee

+ 11 - 8
src/main/java/com/backendsys/modules/common/config/security/utils/CaptchaUtil.java

@@ -35,26 +35,29 @@ public class CaptchaUtil {
      * 判断是否需要 验证码 (errCount: 错误次数)
      */
     public Boolean isCaptchaRequired(String captchaRedisKey, Integer errCount) {
-        String captchaRedisValue = redisUtil.getCacheObject(captchaRedisKey);
-        if (captchaRedisValue == null && Convert.toInt(captchaRedisValue) > errCount) {
-            return false;
+        Object captchaValue = redisUtil.getCacheObject(captchaRedisKey);
+        if (captchaValue != null) {
+            Integer captchaValueToInt = Convert.toInt(captchaValue);
+            if (captchaValueToInt >= errCount) {
+                return true;
+            }
         }
-        return true;
+        return false;
     }
 
     /**
      * 校验 验证码
      */
     public Boolean isCaptchaValid(String captcha, String captchaRedisKey) {
-        // 如果不是本地开发环境,则执行以下判断
-        String profileActive = env.getProperty("spring.profiles.active");
-        if (!("local".equals(profileActive))) {
+//        // 如果不是本地开发环境,则执行以下判断
+//        String profileActive = env.getProperty("spring.profiles.active");
+//        if (!("local".equals(profileActive))) {
             // 判断验证码是否正确 (是否与Redis中的验证码匹配) (测试环境忽略)
             String captchaRedisValue = redisUtil.getCacheObject(captchaRedisKey);
             if (captchaRedisValue == null || !captchaRedisValue.equalsIgnoreCase(captcha)) {
                 return false;
             }
-        }
+//        }
         return true;
     }
 

+ 8 - 0
src/main/java/com/backendsys/modules/system/controller/SysAuthController.java

@@ -36,11 +36,19 @@ public class SysAuthController {
     public void getCaptcha(HttpServletResponse response) throws IOException {
         sysAuthService.renderCaptcha(response);
     }
+    @Operation(summary = "判断是否需验证码登录状态")
+    @GetMapping("/api/system/auth/checkCaptchaRequired")
+    public Result checkCaptchaRequired(String username) {
+        return Result.success().put("data", sysAuthService.checkCaptchaRequired(username));
+    }
     @Operation(summary = "系统用户登录 (用户名)")
     @PostMapping(value = "/api/system/auth/login")
     public Result systemLogin(@Validated(SysAuth.Login.class) @RequestBody SysAuth sysAuth) {
         return Result.success().put("data", sysAuthService.login(sysAuth));
     }
+
+
+
     // -------------------------------------------------------------------------------------------------
 
     @Anonymous

+ 1 - 0
src/main/java/com/backendsys/modules/system/service/SysAuthService.java

@@ -10,6 +10,7 @@ import java.util.Map;
 public interface SysAuthService {
 
     void renderCaptcha(HttpServletResponse response) throws IOException;
+    Map<String, Object> checkCaptchaRequired(String username);
     List<SysMobileArea> getMobileAreaList(SysMobileArea sysMobileArea);
 
     SysUserInfo login(SysAuth sysAuth);

+ 46 - 29
src/main/java/com/backendsys/modules/system/service/impl/SysAuthServiceImpl.java

@@ -74,11 +74,6 @@ public class SysAuthServiceImpl implements SysAuthService {
     private String REDIS_LOGIN_TOKEN_PREFIX;
     @Value("${spring.application.name}")
     private String APPLICATION_NAME;
-    private String redisKeyOfLogin = APPLICATION_NAME + "-sms-login";
-    private String redisKeyOfRegister = APPLICATION_NAME + "-sms-register";
-    private String redisKeyOfLoginFail = APPLICATION_NAME + "-login-error";
-    private String redisKeyOfRegisterFail = APPLICATION_NAME + "-register-error";
-    private String redisKeyOfCaptchaRequired = APPLICATION_NAME + "-" + httpRequestUtil.getKaptchaKey() + "-required";
 
     @Override
     public void renderCaptcha(HttpServletResponse response) throws IOException {
@@ -108,25 +103,37 @@ public class SysAuthServiceImpl implements SysAuthService {
         responseOutputStream.close();
     }
 
+    // 判断是否需验证码登录状态
+    @Override
+    public Map<String, Object> checkCaptchaRequired(String username) {
+        if (StrUtil.isEmpty(username)) throw new CustException("username 不能为空");
+        Boolean currentCaptchaRequired =  captchaUtil.isCaptchaRequired(APPLICATION_NAME + "-login-required-captcha-" + username, 3);
+        return Map.of("is_captcha_required", currentCaptchaRequired);
+    }
+
     @Override
     public List<SysMobileArea> getMobileAreaList(SysMobileArea sysMobileArea) {
         return sysMobileAreaDao.selectMobileAreaList(sysMobileArea);
     }
 
-    // [方法] 登录失败 (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
+    // [方法] 登录失败 (通用) (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
     private void loginFail(String errMsg, String username, Boolean isIntercept) {
 
-        // 输入错误时,计数器叠加,并且设置重置时间 (会一直叠加)
-        Integer currentErrCount;
-        Object captchaRequired = redisUtil.getCacheObject(redisKeyOfCaptchaRequired);
-        currentErrCount = (captchaRequired == null) ? 1 : (Convert.toInt(captchaRequired) + 1);
-        redisUtil.setCacheObject(redisKeyOfCaptchaRequired, currentErrCount, 1, TimeUnit.MINUTES);
+        // 验证码是否必填
+        Boolean currentCaptchaRequired = captchaUtil.isCaptchaRequired(APPLICATION_NAME + "-login-required-captcha-" + username, 3);
+        System.out.println("(loginFailByUsername) currentCaptchaRequired = " + currentCaptchaRequired);
 
         // 删除图形验证码
         redisUtil.delete(httpRequestUtil.getKaptchaKey());
         // 添加登录错误的冻结标记
-        if (isIntercept) lockStatusUtil.setLockStatus(redisKeyOfLoginFail, username);
-        throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
+        if (isIntercept) lockStatusUtil.setLockStatus(APPLICATION_NAME + "-login-error", username);
+
+        if (currentCaptchaRequired) {
+            throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode(), Map.of("is_captcha_required", true));
+        } else {
+            throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
+        }
+
     }
 
     // [方法] 登录成功
@@ -190,6 +197,16 @@ public class SysAuthServiceImpl implements SysAuthService {
         return sysUserInfo;
     }
 
+    private void setLoginRequired(String key) {
+        Object captchaValue = redisUtil.getCacheObject(APPLICATION_NAME + "-login-required-captcha-" + key);
+        Integer currentErrCount = (captchaValue == null) ? 1 : (Convert.toInt(captchaValue) + 1);
+        redisUtil.setCacheObject(APPLICATION_NAME + "-login-required-captcha-" + key, currentErrCount, 1, TimeUnit.MINUTES);
+        System.out.println("currentErrCount: " + currentErrCount);
+    }
+    private void cleanLoginRequired(String key) {
+        redisUtil.delete(APPLICATION_NAME + "-login-required-captcha-" + key);
+    }
+
     /**
      * 登录 (用户名)
      */
@@ -202,36 +219,36 @@ public class SysAuthServiceImpl implements SysAuthService {
         String captcha = sysAuth.getCaptcha();
 
         // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
-        lockStatusUtil.checkLockStatus(redisKeyOfLoginFail, username);
+        lockStatusUtil.checkLockStatus(APPLICATION_NAME + "-login-error", username);
 
-        // 判断是否需要输入验证码
+        // -- 判断是否需要输入验证码 ----------------------------------------------------
         // - 当输错 3 次密码时,需要输入验证码
         // - 当输错后 1 分钟后重置
-        Boolean isCaptchaRequired = captchaUtil.isCaptchaRequired(redisKeyOfCaptchaRequired, 3);
+        Boolean isCaptchaRequired = captchaUtil.isCaptchaRequired(APPLICATION_NAME + "-login-required-captcha-" + username, 3);
         if (isCaptchaRequired) {
-            if (StrUtil.isEmpty(captcha)) {
-                loginFail("验证码不能为空", username, false);
-                return null;
-            }
-            if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
-                loginFail("验证码错误", username, false);
-                return null;
-            }
+            Boolean isCaptchaEmpty = StrUtil.isEmpty(captcha);
+            Boolean isCpatchaValid = (captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey()));
+            if (isCaptchaEmpty) { loginFail("验证码不能为空", username, false); return null; }
+            if (!isCpatchaValid) { loginFail("验证码错误", username, false); return null; }
         }
+        // --------------------------------------------------------------------------
 
         // [Method] 判断 用户 是否存在 && 密码是否正确
         SysUser sysUser = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
         if (sysUser == null) {
             // [登录失败] 用户不存在
+            setLoginRequired(username); // 输入错误时,计数器叠加,并且设置重置时间 (会一直叠加,直到重置 或 登录成功)
             loginFail("用户名或密码错误", username, true);
             return null;
         } else {
             // [登录失败] 密码不正确
             BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
             if (!encoder.matches(password, sysUser.getPassword())) {
+                setLoginRequired(username); // 输入错误时,计数器叠加,并且设置重置时间 (会一直叠加,直到重置 或 登录成功)
                 loginFail("用户名或密码错误", username, true);
             }
             // [登录成功]
+            cleanLoginRequired(username);
             return loginSuccess(sysUser.getId(), sysAuth.getIs_remember());
         }
 
@@ -249,10 +266,10 @@ public class SysAuthServiceImpl implements SysAuthService {
         Integer phoneValidCode = sysAuthPhone.getPhone_valid_code();
 
         // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
-        lockStatusUtil.checkLockStatus(redisKeyOfLoginFail, phone);
+        lockStatusUtil.checkLockStatus(APPLICATION_NAME + "-login-error", phone);
 
         // 判断短信验证码是否正确
-        String redisKey = redisKeyOfLogin + "-" + phone;
+        String redisKey = APPLICATION_NAME + "-sms-login" + "-" + phone;
         Integer smsCode = redisUtil.getCacheObject(redisKey);
         // 判断是否发送验证码
         if ("false".equals(SMS_DEBUG) && smsCode == null) throw new CustException("请先发送验证码");
@@ -295,8 +312,8 @@ public class SysAuthServiceImpl implements SysAuthService {
         Integer phoneValidCode = sysUserDTO.getPhone_valid_code();
 
         // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
-        lockStatusUtil.checkLockStatus(redisKeyOfRegisterFail, username);
-        lockStatusUtil.checkLockStatus(redisKeyOfRegisterFail, phone);
+        lockStatusUtil.checkLockStatus(APPLICATION_NAME + "-register-error", username);
+        lockStatusUtil.checkLockStatus(APPLICATION_NAME + "-register-error", phone);
 
         // 判断图形验证码是否正确
         if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
@@ -309,7 +326,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         if (sysUser1 != null) throw new CustException("用户名 (" + username + ") 已被注册");
         
         // 判断短信验证码是否正确
-        String redisKey = redisKeyOfLogin + "-" + phone;
+        String redisKey = APPLICATION_NAME + "-sms-login" + "-" + phone;
         Integer smsCode = redisUtil.getCacheObject(redisKey);
         // 判断是否发送验证码
         if ("false".equals(SMS_DEBUG) && smsCode == null) throw new CustException("请先发送验证码");