From bc0a695acaf2b6cb94298cfa40321bffc124475a Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Thu, 7 Sep 2023 14:57:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=99=BB=E5=BD=95=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E6=AC=A1=E6=95=B0=E8=BF=87=E5=A4=9A=E5=8F=91=E9=80=81=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E9=80=9A=E7=9F=A5=E7=AE=A1=E7=90=86=E5=91=98#5621?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/AuthUserServiceImpl.java | 44 ++++++++++-- .../commons/constants/ParamConstants.java | 1 + .../sys/SystemParameterController.java | 28 +++++++- .../io/dataease/ext/ExtSysUserMapper.java | 2 + .../java/io/dataease/ext/ExtSysUserMapper.xml | 44 +++++++----- .../dataease/service/sys/SysUserService.java | 13 ++-- .../dataease/service/system/EmailService.java | 71 ++++++++++++++----- .../system/SystemParameterService.java | 22 ++++-- .../resources/i18n/messages_en_US.properties | 1 + .../resources/i18n/messages_zh_CN.properties | 1 + .../resources/i18n/messages_zh_TW.properties | 1 + .../views/system/sysParam/BasicSetting.vue | 7 ++ .../dto/response/LoginLimitInfo.java | 2 + 13 files changed, 183 insertions(+), 54 deletions(-) diff --git a/core/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java b/core/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java index c65ef79ab6..7d91965883 100644 --- a/core/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java +++ b/core/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java @@ -3,13 +3,13 @@ package io.dataease.auth.service.impl; import io.dataease.auth.api.dto.CurrentRoleDto; import io.dataease.auth.entity.AccountLockStatus; import io.dataease.auth.entity.SysUserEntity; -import io.dataease.commons.constants.ParamConstants; -import io.dataease.commons.utils.CodingUtil; -import io.dataease.exception.DataEaseException; -import io.dataease.ext.*; import io.dataease.auth.service.AuthUserService; import io.dataease.commons.constants.AuthConstants; +import io.dataease.commons.constants.ParamConstants; +import io.dataease.commons.utils.CodingUtil; import io.dataease.commons.utils.LogUtil; +import io.dataease.exception.DataEaseException; +import io.dataease.ext.AuthMapper; import io.dataease.i18n.Translator; import io.dataease.plugins.common.base.domain.SysLoginLimit; import io.dataease.plugins.common.base.domain.SysLoginLimitExample; @@ -27,8 +27,9 @@ import io.dataease.plugins.xpack.ldap.service.LdapXpackService; import io.dataease.plugins.xpack.loginlimit.dto.response.LoginLimitInfo; import io.dataease.plugins.xpack.loginlimit.service.LoginLimitXpackService; import io.dataease.plugins.xpack.oidc.service.OidcXpackService; - import io.dataease.plugins.xpack.wecom.service.WecomXpackService; +import io.dataease.service.sys.SysUserService; +import io.dataease.service.system.EmailService; import io.dataease.service.system.SystemParameterService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -36,6 +37,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -45,6 +47,8 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import static io.dataease.commons.constants.ParamConstants.BASIC.LOCKED_EMAIL; + @Service public class AuthUserServiceImpl implements AuthUserService { @@ -62,6 +66,14 @@ public class AuthUserServiceImpl implements AuthUserService { @Resource private SystemParameterService systemParameterService; + @Resource + private EmailService emailService; + + @Lazy + @Resource + private SysUserService sysUserService; + + /** * 此处需被F2CRealm登录认证调用 也就是说每次请求都会被调用 所以最好加上缓存 * @@ -285,10 +297,30 @@ public class AuthUserServiceImpl implements AuthUserService { sysLoginLimit.setLoginType(logintype); sysLoginLimit.setRecordTime(now); sysLoginLimitMapper.insert(sysLoginLimit); - return lockStatus(username, logintype); + AccountLockStatus accountLockStatus = lockStatus(username, logintype); + if (ObjectUtils.isNotEmpty(accountLockStatus) && accountLockStatus.getLocked()) { + sendLockedEmail(username); + } + return accountLockStatus; } + public void sendLockedEmail(String username) { + String value = systemParameterService.getValue(LOCKED_EMAIL.getValue()); + if (StringUtils.isNotBlank(value) && StringUtils.equals("true", value)) { + String email = sysUserService.adminEmail(); + if (StringUtils.isBlank(email)) return; + String format = "账号【%s】登录失败次数过多,已被锁定!"; + String content = String.format(format, username); + try { + emailService.send(email, "账号锁定通知", content); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + systemParameterService.disabledLockedEmail(); + } + } + } + @Override public void unlockAccount(String username, Integer logintype) { SysLoginLimitExample example = new SysLoginLimitExample(); diff --git a/core/backend/src/main/java/io/dataease/commons/constants/ParamConstants.java b/core/backend/src/main/java/io/dataease/commons/constants/ParamConstants.java index 7c67ca446a..556aa7fab4 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/ParamConstants.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/ParamConstants.java @@ -125,6 +125,7 @@ public interface ParamConstants { LOGIN_LIMIT_RELIEVETIMES("loginlimit.relieveTimes"), LOGIN_LIMIT_OPEN("loginlimit.open"), + LOCKED_EMAIL("loginlimit.lockedEmail"), SCAN_CREATE_USER("loginlimit.scanCreateUser"), diff --git a/core/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java b/core/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java index 63d59752b4..29d0a29450 100644 --- a/core/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java +++ b/core/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java @@ -1,29 +1,34 @@ package io.dataease.controller.sys; -import io.dataease.plugins.common.base.domain.SystemParameter; import io.dataease.commons.constants.ParamConstants; +import io.dataease.commons.utils.LogUtil; +import io.dataease.controller.ResultHolder; import io.dataease.controller.sys.response.BasicInfo; import io.dataease.controller.sys.response.MailInfo; import io.dataease.dto.SystemParameterDTO; import io.dataease.listener.DatasetCheckListener; import io.dataease.listener.util.CacheUtils; +import io.dataease.plugins.common.base.domain.SystemParameter; import io.dataease.plugins.common.util.GlobalFileUtil; import io.dataease.plugins.xpack.cas.dto.CasSaveResult; import io.dataease.service.FileService; +import io.dataease.service.sys.SysUserService; import io.dataease.service.system.EmailService; import io.dataease.service.system.SystemParameterService; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.core.io.ByteArrayResource; -import org.springframework.http.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import springfox.documentation.annotations.ApiIgnore; import javax.annotation.Resource; import java.io.IOException; - import java.net.URLDecoder; import java.util.HashMap; import java.util.List; @@ -42,6 +47,23 @@ public class SystemParameterController { @Resource private EmailService emailService; + @Resource + private SysUserService sysUserService; + + @PostMapping("/email/checkAdmin") + public ResultHolder checkAdminEmail() { + String email = sysUserService.adminEmail(); + if (StringUtils.isBlank(email)) { + return ResultHolder.error("管理员邮箱地址为空,请尽快配置"); + } + try { + emailService.testConnection(email); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + return ResultHolder.error(e.getMessage()); + } + return ResultHolder.success(true); + } @RequiresPermissions("sysparam:read") @GetMapping("/mail/info") diff --git a/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.java b/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.java index 799fbf95dc..37996adfe1 100644 --- a/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.java +++ b/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.java @@ -9,4 +9,6 @@ public interface ExtSysUserMapper { List query(GridExample example); List ldapUserNames(Integer from); + + String queryAdminEmail(); } diff --git a/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.xml b/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.xml index 7a8066ec89..c4921381fa 100644 --- a/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.xml +++ b/core/backend/src/main/java/io/dataease/ext/ExtSysUserMapper.xml @@ -2,25 +2,27 @@ - + - + - + - - + + - + - - select r.role_id, r.name as role_name from sys_users_roles sur - left join sys_role r on r.role_id = sur.role_id + left join sys_role r on r.role_id = sur.role_id where sur.user_id = #{user_id} + + diff --git a/core/backend/src/main/java/io/dataease/service/sys/SysUserService.java b/core/backend/src/main/java/io/dataease/service/sys/SysUserService.java index bd97baded8..39dcdc5167 100644 --- a/core/backend/src/main/java/io/dataease/service/sys/SysUserService.java +++ b/core/backend/src/main/java/io/dataease/service/sys/SysUserService.java @@ -3,16 +3,16 @@ package io.dataease.service.sys; import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.auth.service.AuthUserService; import io.dataease.auth.service.ExtAuthService; -import io.dataease.commons.exception.DEException; -import io.dataease.controller.sys.request.*; -import io.dataease.ext.ExtSysUserMapper; -import io.dataease.ext.query.GridExample; import io.dataease.commons.constants.AuthConstants; +import io.dataease.commons.exception.DEException; import io.dataease.commons.utils.AuthUtils; import io.dataease.commons.utils.BeanUtils; import io.dataease.commons.utils.CodingUtil; +import io.dataease.controller.sys.request.*; import io.dataease.controller.sys.response.SysUserGridResponse; import io.dataease.controller.sys.response.SysUserRole; +import io.dataease.ext.ExtSysUserMapper; +import io.dataease.ext.query.GridExample; import io.dataease.i18n.Translator; import io.dataease.plugins.common.base.domain.*; import io.dataease.plugins.common.base.mapper.SysUserAssistMapper; @@ -23,7 +23,6 @@ import io.dataease.plugins.xpack.dingtalk.dto.response.DingUserEntity; import io.dataease.plugins.xpack.lark.dto.entity.LarkUserInfo; import io.dataease.plugins.xpack.larksuite.dto.entity.UserData; import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo; - import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -33,7 +32,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -605,4 +603,7 @@ public class SysUserService { sysUserMapper.updateByPrimaryKeySelective(sysUser); } + public String adminEmail() { + return extSysUserMapper.queryAdminEmail(); + } } diff --git a/core/backend/src/main/java/io/dataease/service/system/EmailService.java b/core/backend/src/main/java/io/dataease/service/system/EmailService.java index e1578c352a..a888ea27b8 100644 --- a/core/backend/src/main/java/io/dataease/service/system/EmailService.java +++ b/core/backend/src/main/java/io/dataease/service/system/EmailService.java @@ -277,6 +277,60 @@ public class EmailService { }); } + private JavaMailSenderImpl buildSender() { + MailInfo mailInfo = proxy().mailInfo(); + checkMailInfo(mailInfo); + JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); + javaMailSender.setDefaultEncoding("UTF-8"); + javaMailSender.setHost(mailInfo.getHost()); + javaMailSender.setPort(Integer.parseInt(mailInfo.getPort())); + javaMailSender.setUsername(mailInfo.getAccount()); + javaMailSender.setPassword(mailInfo.getPassword()); + Properties props = new Properties(); + if (BooleanUtils.toBoolean(mailInfo.getSsl())) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + } + if (BooleanUtils.toBoolean(mailInfo.getTls())) { + props.put("mail.smtp.starttls.enable", "true"); + } + props.put("mail.smtp.timeout", "30000"); + props.put("mail.smtp.connectiontimeout", "10000"); + javaMailSender.setJavaMailProperties(props); + return javaMailSender; + } + + private void testSendEmail(String recipients, JavaMailSenderImpl javaMailSender, boolean isAdmin) { + if (!StringUtils.isBlank(recipients)) { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper; + try { + helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(javaMailSender.getUsername()); + helper.setSubject("DataEase测试邮件 "); + helper.setText("这是一封测试邮件,邮件发送成功", true); + helper.setTo(recipients); + javaMailSender.send(mimeMessage); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + String key = "connection_failed"; + if (isAdmin) key = "connection_failed_admin"; + DEException.throwException(Translator.get(key)); + } + } + } + + public void testConnection(String email) { + JavaMailSenderImpl javaMailSender = null; + try { + javaMailSender = buildSender(); + javaMailSender.testConnection(); + } catch (MessagingException e) { + LogUtil.error(e.getMessage(), e); + DEException.throwException(Translator.get("connection_failed")); + } + testSendEmail(email, javaMailSender, true); + } + public void testConnection(HashMap hashMap) { JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); javaMailSender.setDefaultEncoding("UTF-8"); @@ -301,21 +355,6 @@ public class EmailService { LogUtil.error(e.getMessage(), e); DEException.throwException(Translator.get("connection_failed")); } - if (!StringUtils.isBlank(recipients)) { - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - MimeMessageHelper helper; - try { - helper = new MimeMessageHelper(mimeMessage, true); - helper.setFrom(javaMailSender.getUsername()); - helper.setSubject("DataEase测试邮件 "); - helper.setText("这是一封测试邮件,邮件发送成功", true); - helper.setTo(recipients); - javaMailSender.send(mimeMessage); - } catch (Exception e) { - LogUtil.error(e.getMessage(), e); - DEException.throwException(Translator.get("connection_failed")); - } - } - + testSendEmail(recipients, javaMailSender, false); } } diff --git a/core/backend/src/main/java/io/dataease/service/system/SystemParameterService.java b/core/backend/src/main/java/io/dataease/service/system/SystemParameterService.java index 29ee567046..b0f5402b69 100644 --- a/core/backend/src/main/java/io/dataease/service/system/SystemParameterService.java +++ b/core/backend/src/main/java/io/dataease/service/system/SystemParameterService.java @@ -7,6 +7,7 @@ import io.dataease.commons.utils.EncryptUtils; import io.dataease.controller.sys.response.BasicInfo; import io.dataease.dto.SystemParameterDTO; import io.dataease.exception.DataEaseException; +import io.dataease.ext.ExtSystemParameterMapper; import io.dataease.plugins.common.base.domain.FileMetadata; import io.dataease.plugins.common.base.domain.SystemParameter; import io.dataease.plugins.common.base.domain.SystemParameterExample; @@ -26,6 +27,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import springfox.documentation.annotations.Cacheable; import javax.annotation.Resource; import javax.imageio.ImageIO; @@ -34,9 +36,6 @@ import java.io.InputStream; import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import io.dataease.ext.*; -import springfox.documentation.annotations.Cacheable; - @Service @Transactional(rollbackFor = Exception.class) public class SystemParameterService { @@ -129,6 +128,10 @@ public class SystemParameterService { boolean open = StringUtils.equals("true", param.getParamValue()); result.setOpen(open ? "true" : "false"); } + if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.LOCKED_EMAIL.getValue())) { + boolean open = StringUtils.equals("true", param.getParamValue()); + result.setLockedEmail(open ? "true" : "false"); + } if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.SCAN_CREATE_USER.getValue())) { boolean open = StringUtils.equals("true", param.getParamValue()); result.setScanCreateUser(open ? "true" : "false"); @@ -166,8 +169,7 @@ public class SystemParameterService { CasSaveResult casSaveResult = afterSwitchDefaultLogin(parameters); BasicInfo basicInfo = basicInfo(); String oldMultiLogin = this.getValue("loginlimit.multiLogin"); - for (int i = 0; i < parameters.size(); i++) { - SystemParameter parameter = parameters.get(i); + for (SystemParameter parameter : parameters) { SystemParameterExample example = new SystemParameterExample(); example.createCriteria().andParamKeyEqualTo(parameter.getParamKey()); @@ -280,6 +282,16 @@ public class SystemParameterService { return param.getParamValue(); } + public void disabledLockedEmail() { + SystemParameter param = systemParameterMapper.selectByPrimaryKey(ParamConstants.BASIC.LOCKED_EMAIL.getValue()); + if (ObjectUtils.isNotEmpty(param)) { + SystemParameterExample example = new SystemParameterExample(); + example.createCriteria().andParamKeyEqualTo(ParamConstants.BASIC.LOCKED_EMAIL.getValue()); + param.setParamValue("false"); + systemParameterMapper.updateByExample(param, example); + } + } + public Integer defaultLoginType() { String value = getValue(LOGIN_TYPE_KEY); return StringUtils.isNotBlank(value) ? Integer.parseInt(value) : 0; diff --git a/core/backend/src/main/resources/i18n/messages_en_US.properties b/core/backend/src/main/resources/i18n/messages_en_US.properties index 5583a54bf4..090389c5c3 100644 --- a/core/backend/src/main/resources/i18n/messages_en_US.properties +++ b/core/backend/src/main/resources/i18n/messages_en_US.properties @@ -129,6 +129,7 @@ i18n_field_name_repeat=Field name can't repeat i18n_calc_field_error=Field expression error i18n_cp_exist=Column permission of the same type already exists connection_failed=Connection Failed +connection_failed_admin=Connection failed, please check email configuration or administrator mailbox theme_name_repeat=name of theme has been existed theme_name_empty=name can not be empty i18n_public_chart=\u3010Public Chart\u3011 diff --git a/core/backend/src/main/resources/i18n/messages_zh_CN.properties b/core/backend/src/main/resources/i18n/messages_zh_CN.properties index 7a2810cf0f..05b70ad31a 100644 --- a/core/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/core/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -129,6 +129,7 @@ i18n_field_name_repeat=\u5B57\u6BB5\u540D\u4E0D\u80FD\u91CD\u590D i18n_calc_field_error=\u5B57\u6BB5\u8868\u8FBE\u5F0F\u8BED\u6CD5\u9519\u8BEF i18n_cp_exist=\u5DF2\u6709\u540C\u7C7B\u578B\u7684\u5217\u6743\u9650\u5B58\u5728 connection_failed=\u8FDE\u63A5\u5931\u8D25 +connection_failed_admin=\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u90AE\u4EF6\u914D\u7F6E\u6216\u7BA1\u7406\u5458\u90AE\u7BB1 theme_name_repeat=\u540D\u79F0\u5DF2\u5B58\u5728 theme_name_empty=\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A i18n_public_chart=\u3010\u5B58\u91CF\u89C6\u56FE\u3011 diff --git a/core/backend/src/main/resources/i18n/messages_zh_TW.properties b/core/backend/src/main/resources/i18n/messages_zh_TW.properties index acc0018ed3..f4c4df9008 100644 --- a/core/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/core/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -129,6 +129,7 @@ i18n_field_name_repeat=\u5B57\u6BB5\u540D\u4E0D\u80FD\u91CD\u5FA9 i18n_calc_field_error=\u5B57\u6BB5\u8868\u9054\u5F0F\u8A9E\u6CD5\u932F\u8AA4 i18n_cp_exist=\u5DF2\u6709\u540C\u985E\u578B\u7684\u5217\u6B0A\u9650\u5B58\u5728 connection_failed=\u9023\u63A5\u5931\u6557 +connection_failed_admin=\u9023\u63A5\u5931\u6557\uFF0C\u8ACB\u6AA2\u67E5\u90F5\u4EF6\u914D\u7F6E\u6216\u7BA1\u7406\u54E1\u90F5\u7BB1 theme_name_repeat=\u540D\u7A31\u5DF2\u5B58\u5728 theme_name_empty=\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A i18n_public_chart=\u3010\u5B58\u91CF\u89C6\u56FE\u3011 diff --git a/core/frontend/src/views/system/sysParam/BasicSetting.vue b/core/frontend/src/views/system/sysParam/BasicSetting.vue index e7db140ee8..7d34229fcd 100644 --- a/core/frontend/src/views/system/sysParam/BasicSetting.vue +++ b/core/frontend/src/views/system/sysParam/BasicSetting.vue @@ -366,6 +366,7 @@ export default { this.originLoginType = this.formInline.loginType } this.formInline.open = (this.formInline.open && this.formInline.open === 'true') + this.formInline.lockedEmail = this.formInline?.lockedEmail === 'true' this.formInline.scanCreateUser = (this.formInline.scanCreateUser && this.formInline.scanCreateUser === 'true') this.$nextTick(() => { @@ -455,6 +456,12 @@ export default { type: 'text', sort: 3 }, + { + paramKey: 'loginlimit.lockedEmail', + paramValue: this.formInline.lockedEmail, + type: 'text', + sort: 4 + }, { paramKey: 'loginlimit.scanCreateUser', paramValue: this.formInline.scanCreateUser, diff --git a/sdk/dataease-plugin-interface/src/main/java/io/dataease/plugins/xpack/loginlimit/dto/response/LoginLimitInfo.java b/sdk/dataease-plugin-interface/src/main/java/io/dataease/plugins/xpack/loginlimit/dto/response/LoginLimitInfo.java index f076213d9f..59344be9bb 100644 --- a/sdk/dataease-plugin-interface/src/main/java/io/dataease/plugins/xpack/loginlimit/dto/response/LoginLimitInfo.java +++ b/sdk/dataease-plugin-interface/src/main/java/io/dataease/plugins/xpack/loginlimit/dto/response/LoginLimitInfo.java @@ -14,4 +14,6 @@ public class LoginLimitInfo { private String scanCreateUser; private String multiLogin; + + private String lockedEmail = "false"; }