diff --git a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java index 6f12df6c5..2d6d5e04f 100644 --- a/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java +++ b/kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/auth/LoginService.java @@ -91,54 +91,25 @@ public class LoginService { */ public LoginResponse loginAction(LoginRequest loginRequest, Boolean validatePassword, String caToken) { + // 校验当前系统是否初始化资源完成,如果资源还没有初始化,提示用户请等一下再登录 + if (!InitScanFlagHolder.getFlag()) { + throw new ScannerException(ScannerExceptionEnum.SYSTEM_RESOURCE_URL_NOT_INIT); + } + // 1.参数为空校验 - this.validateEmptyParams(loginRequest, validatePassword); + validateEmptyParams(loginRequest, validatePassword); // 1.2 判断账号是否密码重试次数过多被冻结 - Integer loginErrorCount = loginErrorCountCacheApi.get(loginRequest.getAccount()); - if (loginErrorCount != null && loginErrorCount >= LoginCacheConstants.MAX_ERROR_LOGIN_COUNT) { - throw new AuthException(AuthExceptionEnum.LOGIN_LOCKED); - } + Integer loginErrorCount = validatePasswordRetryTimes(loginRequest); // 1.3 暂存多租户编码(v7.3.2增加,方便缓存调用过程中获取多租户的前缀) RequestTenantCodeHolder.setTenantCode(loginRequest.getTenantCode()); // 2. 如果开启了验证码校验,则验证当前请求的验证码是否正确 - if (SecurityConfigExpander.getCaptchaOpen()) { - String verKey = loginRequest.getVerKey(); - String verCode = loginRequest.getVerCode(); - - if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verCode)) { - throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY); - } - if (!captchaApi.validateCaptcha(verKey, verCode)) { - throw new AuthException(ValidatorExceptionEnum.CAPTCHA_ERROR); - } - } - - // 2.1 验证拖拽验证码 - if (SecurityConfigExpander.getDragCaptchaOpen()) { - String verKey = loginRequest.getVerKey(); - String verXLocationValue = loginRequest.getVerCode(); - - if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verXLocationValue)) { - throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY); - } - if (!dragCaptchaApi.validateCaptcha(verKey, Convert.toInt(verXLocationValue))) { - throw new AuthException(ValidatorExceptionEnum.DRAG_CAPTCHA_ERROR); - } - } - - // 2.2 校验当前系统是否初始化资源完成,如果资源还没有初始化,提示用户请等一下再登录 - if (!InitScanFlagHolder.getFlag()) { - throw new ScannerException(ScannerExceptionEnum.SYSTEM_RESOURCE_URL_NOT_INIT); - } + validateCaptcha(loginRequest); // 3. 解密密码的密文,需要sys_config相关配置打开 - if (loginRequest.getPassword() != null && AuthConfigExpander.getPasswordRsaValidateFlag()) { - String decryptPassword = passwordTransferEncryptApi.decrypt(loginRequest.getPassword()); - loginRequest.setPassword(decryptPassword); - } + decryptRequestPassword(loginRequest); // 4. 如果开启了单点登录,并且CaToken没有值,走单点登录,获取loginCode if (ssoProperties.getOpenFlag() && StrUtil.isEmpty(caToken)) { @@ -171,23 +142,23 @@ public class LoginService { // 8. 生成用户的token DefaultJwtPayload defaultJwtPayload = new DefaultJwtPayload(userValidateInfo.getUserId(), loginRequest.getAccount(), loginRequest.getRememberMe(), caToken, loginRequest.getTenantCode()); - String jwtToken = AuthJwtContext.me().generateTokenDefaultPayload(defaultJwtPayload); + String userLoginToken = AuthJwtContext.me().generateTokenDefaultPayload(defaultJwtPayload); // 9. 创建loginUser对象 - LoginUser loginUser = new LoginUser(userValidateInfo.getUserId(), jwtToken); + LoginUser loginUser = new LoginUser(userValidateInfo.getUserId(), userLoginToken); synchronized (loginRequest.getAccount().intern()) { // 10. 缓存用户信息,创建会话 - sessionManagerApi.createSession(jwtToken, loginUser); + sessionManagerApi.createSession(userLoginToken, loginUser); // 11. 如果开启了单账号单端在线,则踢掉已经上线的该用户 if (AuthConfigExpander.getSingleAccountLoginFlag()) { - sessionManagerApi.removeSessionExcludeToken(jwtToken); + sessionManagerApi.removeSessionExcludeToken(userLoginToken); } } - // 演示环境,跳过记录日志 + // 演示环境,跳过记录日志,非演示环境则记录登录日志 if (!DemoConfigExpander.getDemoEnvFlag()) { // 12. 更新用户登录时间和ip String ip = HttpServletUtil.getRequestClientIp(HttpServletUtil.getRequest()); @@ -201,7 +172,67 @@ public class LoginService { loginErrorCountCacheApi.remove(loginRequest.getAccount()); // 14. 组装返回结果 - return new LoginResponse(loginUser.getUserId(), jwtToken); + return new LoginResponse(loginUser.getUserId(), userLoginToken); + } + + /** + * 如果开启了密码加密配置,则需要进行密码的密文解密,再进行密码校验 + * + * @author fengshuonan + * @since 2023/6/20 23:15 + */ + private void decryptRequestPassword(LoginRequest loginRequest) { + if (loginRequest.getPassword() != null && AuthConfigExpander.getPasswordRsaValidateFlag()) { + String decryptPassword = passwordTransferEncryptApi.decrypt(loginRequest.getPassword()); + loginRequest.setPassword(decryptPassword); + } + } + + /** + * 校验用户的图形验证码,或者拖拽验证码是否正确 + * + * @author fengshuonan + * @since 2023/6/20 23:13 + */ + private void validateCaptcha(LoginRequest loginRequest) { + if (SecurityConfigExpander.getCaptchaOpen()) { + String verKey = loginRequest.getVerKey(); + String verCode = loginRequest.getVerCode(); + + if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verCode)) { + throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY); + } + if (!captchaApi.validateCaptcha(verKey, verCode)) { + throw new AuthException(ValidatorExceptionEnum.CAPTCHA_ERROR); + } + } + + // 2.1 验证拖拽验证码 + if (SecurityConfigExpander.getDragCaptchaOpen()) { + String verKey = loginRequest.getVerKey(); + String verXLocationValue = loginRequest.getVerCode(); + + if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verXLocationValue)) { + throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY); + } + if (!dragCaptchaApi.validateCaptcha(verKey, Convert.toInt(verXLocationValue))) { + throw new AuthException(ValidatorExceptionEnum.DRAG_CAPTCHA_ERROR); + } + } + } + + /** + * 校验密码重试次数是否过多,默认不能超过5次 + * + * @author fengshuonan + * @since 2023/6/20 23:13 + */ + private Integer validatePasswordRetryTimes(LoginRequest loginRequest) { + Integer loginErrorCount = loginErrorCountCacheApi.get(loginRequest.getAccount()); + if (loginErrorCount != null && loginErrorCount >= LoginCacheConstants.MAX_ERROR_LOGIN_COUNT) { + throw new AuthException(AuthExceptionEnum.LOGIN_LOCKED); + } + return loginErrorCount; } /** @@ -271,45 +302,47 @@ public class LoginService { private void validateUserPassword(Boolean validatePassword, Integer loginErrorCount, LoginRequest loginRequest, UserValidateDTO userValidateInfo) { + // 如果不需要校验登录密码,则直接返回 + if (!validatePassword) { + return; + } + // 如果本次登录需要校验密码 - if (validatePassword) { - Boolean checkResult = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), - userValidateInfo.getUserPasswordHexed()); + Boolean checkResult = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), userValidateInfo.getUserPasswordHexed()); - // 校验用户表密码是否正确,如果正确则直接返回 - if (checkResult) { - return; - } + // 校验用户表密码是否正确,如果正确则直接返回 + if (checkResult) { + return; + } - // 如果密码不正确则校验用户是否有临时秘钥 - TempSecretApi tempSecretApi = null; - try { - tempSecretApi = SpringUtil.getBean(TempSecretApi.class); - if (tempSecretApi != null) { - String userTempSecretKey = tempSecretApi.getUserTempSecretKey(userValidateInfo.getUserId()); - // 如果用户有临时秘钥,则校验秘钥是否正确 - if (StrUtil.isNotBlank(userTempSecretKey)) { - Boolean checkTempKeyResult = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), userTempSecretKey); - if (checkTempKeyResult) { - return; - } + // 如果密码不正确则校验用户是否有临时秘钥 + TempSecretApi tempSecretApi = null; + try { + tempSecretApi = SpringUtil.getBean(TempSecretApi.class); + if (tempSecretApi != null) { + String userTempSecretKey = tempSecretApi.getUserTempSecretKey(userValidateInfo.getUserId()); + // 如果用户有临时秘钥,则校验秘钥是否正确 + if (StrUtil.isNotBlank(userTempSecretKey)) { + Boolean checkTempKeyResult = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), userTempSecretKey); + if (checkTempKeyResult) { + return; } } - } catch (Exception ignored) { } - - // 临时秘钥校验完成,返回前端用户密码错误 - if (loginErrorCount == null) { - loginErrorCount = 0; - } - - // 演示环境,不记录error次数 - if (!DemoConfigExpander.getDemoEnvFlag()) { - loginErrorCountCacheApi.put(loginRequest.getAccount(), loginErrorCount + 1); - } - - throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR); + } catch (Exception ignored) { } + + // 临时秘钥校验完成,返回前端用户密码错误 + if (loginErrorCount == null) { + loginErrorCount = 0; + } + + // 演示环境,不记录error次数 + if (!DemoConfigExpander.getDemoEnvFlag()) { + loginErrorCountCacheApi.put(loginRequest.getAccount(), loginErrorCount + 1); + } + + throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR); } }