Merge pull request #3117 from dataease/pr@dev@feat_login_limit

feat(系统管理-用户管理): 登录限制以及解锁用户
This commit is contained in:
xuwei-fit2cloud 2022-09-20 17:04:10 +08:00 committed by GitHub
commit 44206c07ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 437 additions and 122 deletions

View File

@ -0,0 +1,13 @@
package io.dataease.auth.entity;
import lombok.Data;
@Data
public class AccountLockStatus {
private Boolean locked = false;
private String username;
private Long unlockTime;
}

View File

@ -5,6 +5,7 @@ import io.dataease.auth.api.dto.CurrentRoleDto;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.auth.api.dto.LoginDto;
import io.dataease.auth.config.RsaProperties;
import io.dataease.auth.entity.AccountLockStatus;
import io.dataease.auth.entity.SysUserEntity;
import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.service.AuthUserService;
@ -67,10 +68,18 @@ public class AuthServer implements AuthApi {
Integer loginType = loginDto.getLoginType();
boolean isSupportLdap = authUserService.supportLdap();
if (loginType == 1 && isSupportLdap) {
AccountLockStatus accountLockStatus = authUserService.lockStatus(username, 1);
if (accountLockStatus.getLocked()) {
String msg = Translator.get("I18N_ACCOUNT_LOCKED");
msg = String.format(msg, username);
DataEaseException.throwException(msg);
}
LdapXpackService ldapXpackService = SpringContextUtil.getBean(LdapXpackService.class);
LdapValidateRequest request = LdapValidateRequest.builder().userName(username).password(pwd).build();
ValidateResult<XpackLdapUserEntity> validateResult = ldapXpackService.login(request);
if (!validateResult.isSuccess()) {
authUserService.recordLoginFail(username, 1);
DataEaseException.throwException(validateResult.getMsg());
}
XpackLdapUserEntity ldapUserEntity = validateResult.getData();
@ -96,20 +105,29 @@ public class AuthServer implements AuthApi {
username = validateResult.getData().getUsername();
}
// 增加ldap登录方式
AccountLockStatus accountLockStatus = authUserService.lockStatus(username, 0);
if (accountLockStatus.getLocked()) {
String msg = Translator.get("I18N_ACCOUNT_LOCKED");
msg = String.format(msg, username);
DataEaseException.throwException(msg);
}
SysUserEntity user = authUserService.getUserByName(username);
if (ObjectUtils.isEmpty(user)) {
DataEaseException.throwException(Translator.get("i18n_id_or_pwd_error"));
authUserService.recordLoginFail(username, 0);
DataEaseException.throwException(Translator.get("i18n_user_do_not_exist"));
}
// 验证登录类型是否与用户类型相同
if (!sysUserService.validateLoginType(user.getFrom(), loginType)) {
DataEaseException.throwException(Translator.get("i18n_id_or_pwd_error"));
authUserService.recordLoginFail(username, 0);
DataEaseException.throwException(Translator.get("i18n_login_type_error"));
}
if (user.getEnabled() == 0) {
DataEaseException.throwException(Translator.get("i18n_id_or_pwd_error"));
authUserService.recordLoginFail(username, 0);
DataEaseException.throwException(Translator.get("i18n_user_is_disable"));
}
String realPwd = user.getPassword();
@ -121,6 +139,7 @@ public class AuthServer implements AuthApi {
pwd = CodingUtil.md5(pwd);
if (!StringUtils.equals(pwd, realPwd)) {
authUserService.recordLoginFail(username, 0);
DataEaseException.throwException(Translator.get("i18n_id_or_pwd_error"));
}
}

View File

@ -1,6 +1,7 @@
package io.dataease.auth.service;
import io.dataease.auth.api.dto.CurrentRoleDto;
import io.dataease.auth.entity.AccountLockStatus;
import io.dataease.auth.entity.SysUserEntity;
import java.util.List;
@ -38,9 +39,19 @@ public interface AuthUserService {
Boolean supportLark();
Boolean supportLoginLimit();
Boolean pluginLoaded();
void checkAdmin(String uname, String pwd);
void recordLoginFail(String username, Integer logintype);
void unlockAccount(String username, Integer logintype);
AccountLockStatus lockStatus(String username, Integer logintype);
void clearAllLock();
}

View File

@ -1,6 +1,7 @@
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.utils.CodingUtil;
import io.dataease.exception.DataEaseException;
@ -9,7 +10,10 @@ import io.dataease.auth.service.AuthUserService;
import io.dataease.commons.constants.AuthConstants;
import io.dataease.commons.utils.LogUtil;
import io.dataease.i18n.Translator;
import io.dataease.plugins.common.base.domain.SysLoginLimit;
import io.dataease.plugins.common.base.domain.SysLoginLimitExample;
import io.dataease.plugins.common.base.domain.SysUser;
import io.dataease.plugins.common.base.mapper.SysLoginLimitMapper;
import io.dataease.plugins.common.base.mapper.SysUserMapper;
import io.dataease.plugins.common.service.PluginCommonService;
import io.dataease.plugins.config.SpringContextUtil;
@ -18,9 +22,12 @@ import io.dataease.plugins.xpack.cas.service.CasXpackService;
import io.dataease.plugins.xpack.dingtalk.service.DingtalkXpackService;
import io.dataease.plugins.xpack.lark.service.LarkXpackService;
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 org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
@ -46,6 +53,9 @@ public class AuthUserServiceImpl implements AuthUserService {
@Resource
private DynamicMenuServiceImpl dynamicMenuService;
@Resource
private SysLoginLimitMapper sysLoginLimitMapper;
/**
* 此处需被F2CRealm登录认证调用 也就是说每次请求都会被调用 所以最好加上缓存
*
@ -196,6 +206,15 @@ public class AuthUserServiceImpl implements AuthUserService {
return larkXpackService.isOpen();
}
@Override
public Boolean supportLoginLimit() {
Map<String, LoginLimitXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((LoginLimitXpackService.class));
if (beansOfType.keySet().size() == 0) return false;
LoginLimitXpackService loginLimitXpackService = SpringContextUtil.getBean(LoginLimitXpackService.class);
if (ObjectUtils.isEmpty(loginLimitXpackService)) return false;
return loginLimitXpackService.isOpen();
}
@Override
public Boolean pluginLoaded() {
Map<String, PluginCommonService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((PluginCommonService.class));
@ -221,4 +240,61 @@ public class AuthUserServiceImpl implements AuthUserService {
DataEaseException.throwException(Translator.get("i18n_id_or_pwd_error"));
}
}
@Override
public void recordLoginFail(String username, Integer logintype) {
if (!supportLoginLimit()) return;
long now = System.currentTimeMillis();
SysLoginLimit sysLoginLimit = new SysLoginLimit();
sysLoginLimit.setUsername(username);
sysLoginLimit.setLoginType(logintype);
sysLoginLimit.setRecordTime(now);
sysLoginLimitMapper.insert(sysLoginLimit);
}
@Override
public void unlockAccount(String username, Integer logintype) {
SysLoginLimitExample example = new SysLoginLimitExample();
example.createCriteria().andUsernameEqualTo(username).andLoginTypeEqualTo(logintype);
sysLoginLimitMapper.deleteByExample(example);
}
@Override
public AccountLockStatus lockStatus(String username, Integer logintype) {
AccountLockStatus accountLockStatus = new AccountLockStatus();
accountLockStatus.setUsername(username);
if (!supportLoginLimit()) return accountLockStatus;
LoginLimitXpackService loginLimitXpackService = SpringContextUtil.getBean(LoginLimitXpackService.class);
LoginLimitInfo info = loginLimitXpackService.info();
Integer limitTimes = info.getLimitTimes();
Integer relieveTimes = info.getRelieveTimes();
long now = System.currentTimeMillis();
long longRelieveTimes = Long.parseLong(relieveTimes.toString());
long dividingPointTime = now - (longRelieveTimes * 60L * 1000L);
SysLoginLimitExample example = new SysLoginLimitExample();
example.createCriteria().andUsernameEqualTo(username).andLoginTypeEqualTo(logintype).andRecordTimeGreaterThan(dividingPointTime);
List<SysLoginLimit> sysLoginLimits = sysLoginLimitMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(sysLoginLimits)) {
boolean needLock = sysLoginLimits.size() >= limitTimes;
accountLockStatus.setLocked(needLock);
if (needLock) {
long unlockTime = now + (longRelieveTimes * 60L * 1000L);
accountLockStatus.setUnlockTime(unlockTime);
}
}
example.clear();
example.createCriteria().andUsernameEqualTo(username).andLoginTypeEqualTo(logintype).andRecordTimeLessThanOrEqualTo(dividingPointTime);
sysLoginLimitMapper.deleteByExample(example);
return accountLockStatus;
}
@Override
public void clearAllLock() {
SysLoginLimitExample example = new SysLoginLimitExample();
sysLoginLimitMapper.deleteByExample(example);
}
}

View File

@ -117,6 +117,12 @@ public interface ParamConstants {
OPEN_MARKET_PAGE("ui.openMarketPage"),
TEMPLATE_MARKET_ULR("basic.templateMarketUlr"),
LOGIN_LIMIT_LIMITTIMES("loginlimit.limitTimes"),
LOGIN_LIMIT_RELIEVETIMES("loginlimit.relieveTimes"),
LOGIN_LIMIT_OPEN("loginlimit.open"),
TEMPLATE_ACCESS_KEY("basic.templateAccessKey");
private String value;

View File

@ -5,6 +5,8 @@ import com.github.pagehelper.PageHelper;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.auth.annotation.DeLog;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.auth.entity.AccountLockStatus;
import io.dataease.auth.service.AuthUserService;
import io.dataease.commons.constants.SysLogConstants;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.controller.sys.request.KeyGridRequest;
@ -21,6 +23,7 @@ import io.dataease.controller.sys.request.SysUserPwdRequest;
import io.dataease.controller.sys.request.SysUserStateRequest;
import io.dataease.controller.sys.response.RoleUserItem;
import io.dataease.controller.sys.response.SysUserGridResponse;
import io.dataease.plugins.common.base.domain.SysUser;
import io.dataease.service.sys.SysRoleService;
import io.dataease.service.sys.SysUserService;
import io.swagger.annotations.Api;
@ -51,6 +54,9 @@ public class SysUserController {
@Resource
private SysRoleService sysRoleService;
@Resource
private AuthUserService authUserService;
@ApiOperation("查询用户")
@RequiresPermissions("user:read")
@PostMapping("/userGrid/{goPage}/{pageSize}")
@ -62,7 +68,12 @@ public class SysUserController {
public Pager<List<SysUserGridResponse>> userGrid(@PathVariable int goPage, @PathVariable int pageSize,
@RequestBody KeyGridRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, sysUserService.query(request));
List<SysUserGridResponse> users = sysUserService.query(request);
users.forEach(user -> {
AccountLockStatus accountLockStatus = authUserService.lockStatus(user.getUsername(), user.getFrom());
user.setLocked(accountLockStatus.getLocked());
});
return PageUtils.setPageInfo(page, users);
}
@ApiIgnore
@ -207,4 +218,12 @@ public class SysUserController {
}).collect(Collectors.toList());
}
@PostMapping("/unlock/{username}")
public void unlock(@PathVariable("username") String username) {
SysUser sysUser = new SysUser();
sysUser.setUsername(username);
SysUser one = sysUserService.findOne(sysUser);
authUserService.unlockAccount(username, one.getFrom());
}
}

View File

@ -2,11 +2,12 @@ package io.dataease.controller.sys.response;
import java.io.Serializable;
import io.dataease.plugins.xpack.loginlimit.dto.response.LoginLimitInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class BasicInfo implements Serializable {
public class BasicInfo extends LoginLimitInfo implements Serializable {
@ApiModelProperty("请求超时时间")
private String frontTimeOut;

View File

@ -16,5 +16,7 @@ public class SysUserGridResponse extends SysUser {
private SysUserDept dept;
@ApiModelProperty("角色ID集合")
private List<Long> roleIds;
@ApiModelProperty("锁定")
private Boolean locked;
}

View File

@ -15,6 +15,7 @@ import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.cas.dto.CasSaveResult;
import io.dataease.plugins.xpack.cas.service.CasXpackService;
import io.dataease.plugins.xpack.display.service.DisplayXpackService;
import io.dataease.plugins.xpack.loginlimit.service.LoginLimitXpackService;
import io.dataease.service.FileService;
import io.dataease.service.datasource.DatasourceService;
import org.apache.commons.collections.CollectionUtils;
@ -58,10 +59,14 @@ public class SystemParameterService {
List<SystemParameter> paramList = this.getParamList("basic");
List<SystemParameter> homePageList = this.getParamList("ui.openHomePage");
List<SystemParameter> marketPageList = this.getParamList("ui.openMarketPage");
List<SystemParameter> loginLimitList = this.getParamList("loginlimit");
paramList.addAll(homePageList);
paramList.addAll(marketPageList);
paramList.addAll(loginLimitList);
BasicInfo result = new BasicInfo();
result.setOpenHomePage("true");
Map<String, LoginLimitXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((LoginLimitXpackService.class));
Boolean loginLimitPluginLoaded = beansOfType.keySet().size() > 0;
if (!CollectionUtils.isEmpty(paramList)) {
for (SystemParameter param : paramList) {
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.FRONT_TIME_OUT.getValue())) {
@ -94,6 +99,27 @@ public class SystemParameterService {
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.DS_CHECK_INTERVAL_TYPE.getValue())) {
result.setDsCheckIntervalType(param.getParamValue());
}
if (loginLimitPluginLoaded) {
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.LOGIN_LIMIT_LIMITTIMES.getValue())) {
String paramValue = param.getParamValue();
if (StringUtils.isNotBlank(paramValue)) {
result.setLimitTimes(Integer.parseInt(paramValue));
}
}
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.LOGIN_LIMIT_RELIEVETIMES.getValue())) {
String paramValue = param.getParamValue();
if (StringUtils.isNotBlank(paramValue)) {
result.setRelieveTimes(Integer.parseInt(paramValue));
}
}
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.LOGIN_LIMIT_OPEN.getValue())) {
boolean open = StringUtils.equals("true", param.getParamValue());
result.setOpen(open ? "true" : "false");
}
}
}
}
return result;

View File

@ -98,6 +98,15 @@ ALTER TABLE `sys_task_email`
ALTER TABLE `sys_task_email`
ADD COLUMN `reci_users` varchar(255) NULL COMMENT '接收人账号' AFTER `conditions`;
DROP TABLE IF EXISTS `sys_login_limit`;
CREATE TABLE `sys_login_limit` (
`login_type` int(8) NOT NULL,
`username` varchar(255) NOT NULL,
`record_time` bigint(13) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
UPDATE `sys_menu` SET `pid` = 0, `sub_count` = 0, `type` = 1, `title` = '模板市场', `name` = 'template-market', `component` = 'panel/templateMarket/index', `menu_sort` = 5, `icon` = 'dashboard', `path` = '/templateMarket', `i_frame` = 0, `cache` = 0, `hidden` = 0, `permission` = 'template-market:read', `create_by` = NULL, `update_by` = NULL, `create_time` = NULL, `update_time` = 1620444227389 WHERE `menu_id` = 202;
INSERT INTO `sys_auth` (`id`, `auth_source`, `auth_source_type`, `auth_target`, `auth_target_type`, `auth_time`, `auth_details`, `auth_user`, `update_time`, `copy_from`, `copy_id`) VALUES ('e6b2cebf-02d8-4d46-833c-56fb07febb0f', '202', 'menu', '2', 'user', 1663661210626, NULL, 'admin', NULL, NULL, NULL);
@ -106,3 +115,4 @@ INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_typ
INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, `copy_id`) VALUES ('2e9f5ca1-38bb-11ed-8383-0242ac130005', 'e6b2cebf-02d8-4d46-833c-56fb07febb0f', 'i18n_auth_use', 1, 0, 'use', '基础权限-使用', 'admin', 1663661211000, NULL, NULL, NULL);
INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, `copy_id`) VALUES ('98d77463-38bb-11ed-8383-0242ac130005', 'f4e07708-26f1-4f42-9a4a-8e6dae63353c', 'i18n_auth_grant', 15, 0, 'grant', '基础权限-授权', 'admin', 1663661389000, NULL, NULL, NULL);
INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, `copy_id`) VALUES ('98d77856-38bb-11ed-8383-0242ac130005', 'f4e07708-26f1-4f42-9a4a-8e6dae63353c', 'i18n_auth_use', 1, 1, 'use', '基础权限-使用', 'admin', 1663661389000, NULL, NULL, NULL);

View File

@ -72,7 +72,11 @@ i18n_sql_not_empty=SQL can not be empty.
i18n_datasource_not_allow_delete_msg= datasets are using this data source and cannot be deleted
i18n_task_name_repeat=Name is used in same data set
i18n_id_or_pwd_error=Invalid ID or password
i18n_datasource_delete=Data source is delete
i18n_user_do_not_exist=User do not exist
i18n_user_is_disable=User is disabled
i18n_login_type_error=Login type error
i18n_account_is_locked=Account is locked
i18n_datasource_delete=Data source is deleted
i18n_dataset_delete=Data set is deleted
i18n_dataset_no_permission=Data set no permission
i18n_chart_delete=Chart is delete
@ -217,12 +221,17 @@ I18N_STATUS=Status
I18N_DATA=Data
I18N_SYNC_LOG=Sync log
I18N_USER_DONOT_EXIST=User do not exist
I18N_USER_DONOT_EXIST=User does not exist
I18N_USER_SOURCE_PWD_ERROR=Source password error
I18N_USER_PWD_FORMAT_ERROR=Password format error
I18N_DS_INVALID=Datasource is invalid.
I18N_DS_INVALID_TABLE=Datasource has invalid tables
I18N_ACCOUNT_LOCKED=Account\u3010%s\u3011is locked\uFF01
I18N_PANEL_EXIST=The current panel name already exists under this directory
I18N_DATASET_GROUP_EXIST=The current dataset grouping name already exists under this directory

View File

@ -72,6 +72,10 @@ i18n_sql_not_empty=SQL \u4E0D\u80FD\u4E3A\u7A7A
i18n_datasource_not_allow_delete_msg= \u4E2A\u6570\u636E\u96C6\u6B63\u5728\u4F7F\u7528\u6B64\u6570\u636E\u6E90\uFF0C\u65E0\u6CD5\u5220\u9664
i18n_task_name_repeat=\u540C\u4E00\u6570\u636E\u96C6\u4E0B\u4EFB\u52A1\u540D\u79F0\u5DF2\u88AB\u4F7F\u7528
i18n_id_or_pwd_error=\u65E0\u6548\u7684ID\u6216\u5BC6\u7801
i18n_user_do_not_exist=\u7528\u6237\u4E0D\u5B58\u5728
i18n_user_is_disable=\u7528\u6237\u72B6\u6001\u65E0\u6548
i18n_login_type_error=\u767B\u5F55\u65B9\u5F0F\u9519\u8BEF
i18n_account_is_locked=\u8D26\u6237\u5DF2\u9501\u5B9A
i18n_datasource_delete=\u5F53\u524D\u7528\u5230\u7684\u6570\u636E\u6E90\u5DF2\u88AB\u5220\u9664
i18n_dataset_delete=\u5F53\u524D\u7528\u5230\u7684\u6570\u636E\u96C6\u5DF2\u88AB\u5220\u9664
i18n_dataset_no_permission=\u5F53\u524D\u7528\u5230\u7684\u6570\u636E\u96C6\u6CA1\u6709\u6743\u9650
@ -224,5 +228,10 @@ I18N_USER_PWD_FORMAT_ERROR=\u5BC6\u7801\u683C\u5F0F\u9519\u8BEF
I18N_DS_INVALID=\u6570\u636E\u6E90\u65E0\u6548.
I18N_DS_INVALID_TABLE=\u6570\u636E\u6E90\u4E2D\u6709\u65E0\u6548\u7684\u8868
I18N_ACCOUNT_LOCKED=\u8D26\u53F7\u3010%s\u3011\u5DF2\u9501\u5B9A\uFF01
I18N_PANEL_EXIST=\u5F53\u524D\u4EEA\u8868\u677F\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728
I18N_DATASET_GROUP_EXIST=\u5F53\u524D\u6570\u636E\u96C6\u5206\u7EC4\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728

View File

@ -72,6 +72,10 @@ i18n_sql_not_empty=SQL \u4E0D\u80FD\u70BA\u7A7A
i18n_datasource_not_allow_delete_msg= \u500B\u6578\u64DA\u96C6\u6B63\u5728\u4F7F\u7528\u6B64\u6578\u64DA\u6E90\uFF0C\u7121\u6CD5\u522A\u9664
i18n_task_name_repeat=\u540C\u4E00\u6578\u64DA\u96C6\u4E0B\u4EFB\u52D9\u540D\u7A31\u5DF2\u88AB\u4F7F\u7528
i18n_id_or_pwd_error=\u7121\u6548\u7684ID\u6216\u5BC6\u78BC
i18n_user_do_not_exist=\u7528\u6236\u4E0D\u5B58\u5728
i18n_user_is_disable=\u7528\u6236\u72C0\u614B\u7121\u6548
i18n_login_type_error=\u767B\u9304\u65B9\u5F0F\u932F\u8AA4
i18n_account_is_locked=\u8CEC\u6236\u5DF2\u9396\u5B9A
i18n_datasource_delete=\u7576\u524D\u7528\u5230\u7684\u6578\u64DA\u6E90\u5DF2\u88AB\u522A\u9664
i18n_dataset_delete=\u7576\u524D\u7528\u5230\u7684\u6578\u64DA\u96C6\u5DF2\u88AB\u522A\u9664
i18n_dataset_no_permission=\u7576\u524D\u7528\u5230\u7684\u6578\u64DA\u96C6\u6C92\u6709\u6B0A\u9650
@ -220,5 +224,10 @@ I18N_USER_PWD_FORMAT_ERROR=\u5BC6\u78BC\u683C\u5F0F\u932F\u8AA4
I18N_DS_INVALID=\u6578\u64DA\u6E90\u7121\u6548.
I18N_DS_INVALID_TABLE=\u6578\u64DA\u6E90\u4E2D\u6709\u7121\u6548\u7684\u8868
I18N_ACCOUNT_LOCKED=\u8CEC\u865F\u3010%s\u3011\u5DF2\u9396\u5B9A\uFF01
I18N_PANEL_EXIST=\u7576\u524D\u5100\u9336\u95C6\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728
I18N_DATASET_GROUP_EXIST=\u7576\u524D\u6578\u64DA\u96C6\u5206\u7D44\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728

View File

@ -9,7 +9,8 @@ const pathMap = {
createPath: '/api/user/create',
updatePath: '/api/user/update',
editPasswordPath: '/api/user/adminUpdatePwd',
editStatusPath: '/api/user/updateStatus'
editStatusPath: '/api/user/updateStatus',
unlockPath: '/api/user/unlock/'
}
export function userLists(page, size, data) {
return request({
@ -133,4 +134,12 @@ export function existLdapUsers() {
})
}
export default { editPassword, delUser, editUser, addUser, userLists, editStatus, personInfo, updatePerson, updatePersonPwd, allRoles, roleGrid, ldapUsers, saveLdapUser, existLdapUsers }
export function unLock(username) {
return request({
url: pathMap.unlockPath + username,
method: 'post',
loading: false
})
}
export default { editPassword, delUser, editUser, addUser, userLists, editStatus, personInfo, updatePerson, updatePersonPwd, allRoles, roleGrid, ldapUsers, saveLdapUser, existLdapUsers, unLock }

View File

@ -131,7 +131,13 @@ export default {
default_login: 'Normal'
},
commons: {
uninstall: 'Uninstall',
unlock: 'Unlock',
unlock_success: 'Unlock success',
uninstall:'Uninstall',
no_result: 'No Result',
manage_member: 'Managing members',
confirm_remove_cancel: 'Are you sure to delete the role?',

View File

@ -131,7 +131,13 @@ export default {
default_login: '普通登錄'
},
commons: {
uninstall: '卸载',
unlock: '解鎖',
unlock_success: '解鎖成功',
uninstall:'卸载',
no_result: '没有找到相关内容',
manage_member: '管理成員',
user_confirm_remove_cancel: '確定將該用戶從角色中移除嗎?',

View File

@ -131,7 +131,11 @@ export default {
default_login: '普通登录'
},
commons: {
uninstall: '卸载',
unlock: '解锁',
unlock_success: '解锁成功',
uninstall:'卸载',
no_result: '没有找到相关内容',
manage_member: '管理成员',
confirm_remove_cancel: '确定删除该角色吗?',

View File

@ -1,11 +1,11 @@
<template>
<div>
<operater title="system_parameter_setting.basic_setting">
<deBtn type="primary" v-if="showEdit" @click="edit">{{
$t("commons.edit")
<deBtn v-if="showEdit" type="primary" @click="edit">{{
$t("commons.edit")
}}</deBtn>
<deBtn v-if="showCancel" secondary @click="cancel">{{
$t("commons.cancel")
$t("commons.cancel")
}}</deBtn>
<deBtn v-if="showSave" type="primary" :disabled="disabledSave" size="small" @click="save('formInline')">
{{ $t("commons.save") }}
@ -13,26 +13,42 @@
</operater>
<!--基础配置表单-->
<el-form ref="formInline" v-loading="loading" :model="formInline" :rules="rules"
class="demo-form-inline de-form-item" :disabled="show" label-width="80px" label-position="right" size="small">
<el-form
ref="formInline"
v-loading="loading"
:model="formInline"
:rules="rules"
class="demo-form-inline de-form-item"
:disabled="show"
label-width="80px"
label-position="right"
size="small"
>
<el-form-item prop="frontTimeOut">
<template slot="label">
{{ $t('system_parameter_setting.request_timeout')}}
<el-tooltip class="item" effect="dark" :content="$t('system_parameter_setting.front_time_out')"
placement="top">
<i class="el-icon-warning-outline tips"></i>
{{ $t('system_parameter_setting.request_timeout') }}
<el-tooltip
class="item"
effect="dark"
:content="$t('system_parameter_setting.front_time_out')"
placement="top"
>
<i class="el-icon-warning-outline tips" />
</el-tooltip>
</template>
<el-input v-model="formInline.frontTimeOut" :placeholder="$t('system_parameter_setting.empty_front')"><template
slot="append">{{ $t("panel.second") }}</template></el-input>
slot="append"
>{{ $t("panel.second") }}</template></el-input>
</el-form-item>
<el-form-item :label="$t('system_parameter_setting.message_retention_time')" prop="msgTimeOut">
<el-input v-model="formInline.msgTimeOut" :placeholder="$t('system_parameter_setting.empty_msg')"><template
slot="append">{{ $t('components.day') }}</template></el-input>
slot="append"
>{{ $t('components.day') }}</template></el-input>
</el-form-item>
<el-form-item :label="$t('system_parameter_setting.ds_check_time')" >
<el-form-item :label="$t('system_parameter_setting.ds_check_time')">
<el-form :inline="true" :disabled="show">
<el-form-item >
<el-input size="mini" v-model="formInline.dsCheckInterval" type="number" min="1" @change="onSimpleCronChange()" />
</el-form-item>
@ -50,7 +66,7 @@
<el-form-item v-if="loginTypes.length > 1" :label="$t('system_parameter_setting.login_type')" prop="loginType">
<el-radio-group v-model="formInline.loginType">
<el-radio :label="0" size="mini">{{
$t("login.default_login")
$t("login.default_login")
}}</el-radio>
<el-radio v-if="loginTypes.includes(1)" :label="1" size="mini">LDAP</el-radio>
<el-radio v-if="loginTypes.includes(2)" :label="2" size="mini">OIDC</el-radio>
@ -62,18 +78,25 @@
<el-button class="pwd-tips" type="text">{{ $t('system_parameter_setting.cas_reset') + '[/cas/reset/{adminAcount}/{adminPwd}]' }}</el-button>
</el-row> -->
<el-form-item :label="
$t('commons.yes') + $t('commons.no') + $t('display.openMarketPage')
">
<plugin-com v-if="isPluginLoaded" ref="LoginLimitSetting" :form="formInline" component-name="LoginLimitSetting" />
<el-form-item
:label="
$t('commons.yes') + $t('commons.no') + $t('display.openMarketPage')
"
>
<el-radio-group v-model="formInline.openMarketPage">
<el-radio label="true" size="mini">{{ $t("commons.yes") }}</el-radio>
<el-radio label="false" size="mini">{{ $t("commons.no") }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="
$t('commons.yes') + $t('commons.no') + $t('display.openHomePage')
" prop="openHomePage">
<el-form-item
:label="
$t('commons.yes') + $t('commons.no') + $t('display.openHomePage')
"
prop="openHomePage"
>
<el-radio-group v-model="formInline.openHomePage">
<el-radio label="true" size="mini">{{ $t("commons.yes") }}</el-radio>
<el-radio label="false" size="mini">{{ $t("commons.no") }}</el-radio>
@ -84,16 +107,24 @@
</template>
<script>
import { basicInfo, updateInfo } from "@/api/system/basic";
import { ldapStatus, oidcStatus, casStatus } from "@/api/user";
import bus from "@/utils/bus";
import operater from "./operater";
import { basicInfo, updateInfo } from '@/api/system/basic'
import { ldapStatus, oidcStatus, casStatus } from '@/api/user'
import bus from '@/utils/bus'
import operater from './operater'
import msgCfm from '@/components/msgCfm'
import PluginCom from '@/views/system/plugin/PluginCom'
export default {
name: "EmailSetting",
mixins: [msgCfm],
name: 'EmailSetting',
components: {
operater,
PluginCom
},
mixins: [msgCfm],
props: {
isPluginLoaded: {
type: Boolean,
default: false
}
},
data() {
return {
@ -108,169 +139,189 @@ export default {
rules: {
frontTimeOut: [
{
pattern: "^([0-9]|\\b[1-9]\\d\\b|\\b[1-2]\\d\\d\\b|\\b300\\b)$", // 0-300
message: this.$t("system_parameter_setting.front_error"),
trigger: "blur",
},
pattern: '^([0-9]|\\b[1-9]\\d\\b|\\b[1-2]\\d\\d\\b|\\b300\\b)$', // 0-300
message: this.$t('system_parameter_setting.front_error'),
trigger: 'blur'
}
],
msgTimeOut: [
{
pattern: "^([1-9]|[1-9][0-9]|[1-2][0-9][0-9]|3[0-5][0-9]|36[0-5])$",
message: this.$t("system_parameter_setting.msg_error"),
trigger: "blur",
},
],
pattern: '^([1-9]|[1-9][0-9]|[1-2][0-9][0-9]|3[0-5][0-9]|36[0-5])$',
message: this.$t('system_parameter_setting.msg_error'),
trigger: 'blur'
}
]
},
originLoginType: null,
};
originLoginType: null
}
},
computed: {},
beforeCreate() {
ldapStatus().then((res) => {
if (res.success && res.data) {
this.loginTypes.push(1);
this.loginTypes.push(1)
}
});
})
oidcStatus().then((res) => {
if (res.success && res.data) {
this.loginTypes.push(2);
this.loginTypes.push(2)
}
});
})
casStatus().then((res) => {
if (res.success && res.data) {
this.loginTypes.push(3);
this.loginTypes.push(3)
}
});
})
},
created() {
this.query();
this.query()
},
methods: {
query() {
basicInfo().then((response) => {
this.formInline = response.data;
this.formInline = response.data
if (this.formInline && !this.formInline.loginType) {
this.formInline.loginType = 0;
this.formInline.loginType = 0
}
if (!this.originLoginType) {
this.originLoginType = this.formInline.loginType;
this.originLoginType = this.formInline.loginType
}
this.formInline.open = (this.formInline.open && this.formInline.open === 'true')
this.$nextTick(() => {
this.$refs.formInline.clearValidate();
});
});
this.$refs.formInline.clearValidate()
})
})
},
edit() {
this.showEdit = false;
this.showSave = true;
this.showCancel = true;
this.show = false;
this.showEdit = false
this.showSave = true
this.showCancel = true
this.show = false
},
save(formInline) {
const param = [
{
paramKey: "basic.frontTimeOut",
paramKey: 'basic.frontTimeOut',
paramValue: this.formInline.frontTimeOut,
type: "text",
sort: 1,
type: 'text',
sort: 1
},
{
paramKey: "basic.msgTimeOut",
paramKey: 'basic.msgTimeOut',
paramValue: this.formInline.msgTimeOut,
type: "text",
sort: 2,
type: 'text',
sort: 2
},
{
paramKey: "basic.loginType",
paramKey: 'basic.loginType',
paramValue: this.formInline.loginType,
type: "text",
sort: 3,
type: 'text',
sort: 3
},
{
paramKey: "basic.dsCheckInterval",
paramKey: 'basic.dsCheckInterval',
paramValue: this.formInline.dsCheckInterval,
type: "text",
sort: 4,
type: 'text',
sort: 4
},
{
paramKey: "basic.dsCheckIntervalType",
paramKey: 'basic.dsCheckIntervalType',
paramValue: this.formInline.dsCheckIntervalType,
type: "text",
sort: 5,
type: 'text',
sort: 5
},
{
paramKey: "ui.openHomePage",
paramKey: 'ui.openHomePage',
paramValue: this.formInline.openHomePage,
type: "text",
sort: 13,
type: 'text',
sort: 13
},
{
paramKey: "ui.openMarketPage",
paramKey: 'ui.openMarketPage',
paramValue: this.formInline.openMarketPage,
type: "text",
sort: 14,
type: 'text',
sort: 14
},
];
{
paramKey: 'loginlimit.limitTimes',
paramValue: this.formInline.limitTimes,
type: 'text',
sort: 1
},
{
paramKey: 'loginlimit.relieveTimes',
paramValue: this.formInline.relieveTimes,
type: 'text',
sort: 2
},
{
paramKey: 'loginlimit.open',
paramValue: this.formInline.open,
type: 'text',
sort: 3
}
]
this.$refs[formInline].validate((valid) => {
if (valid) {
const needWarn =
this.formInline.loginType === 3 && this.originLoginType !== 3;
this.formInline.loginType === 3 && this.originLoginType !== 3
if (needWarn) {
this.$confirm(
this.$t("system_parameter_setting.cas_selected_warn"),
"",
this.$t('system_parameter_setting.cas_selected_warn'),
'',
{
confirmButtonText: this.$t("commons.confirm"),
cancelButtonText: this.$t("commons.cancel"),
type: "warning",
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning'
}
)
.then(() => {
this.saveHandler(param);
this.saveHandler(param)
})
.catch(() => {
// this.$info(this.$t('commons.delete_cancel'))
});
return;
})
return
}
this.saveHandler(param);
this.saveHandler(param)
} else {
// this.result = false
}
});
})
},
saveHandler(param) {
updateInfo(param).then((response) => {
const flag = response.success;
const flag = response.success
if (flag) {
if (response.data && response.data.needLogout) {
const casEnable = response.data.casEnable;
bus.$emit("sys-logout", { casEnable });
return;
const casEnable = response.data.casEnable
bus.$emit('sys-logout', { casEnable })
return
}
this.openMessageSuccess("commons.save_success");
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
window.location.reload();
this.openMessageSuccess('commons.save_success')
this.showEdit = true
this.showCancel = false
this.showSave = false
this.show = true
window.location.reload()
} else {
this.openMessageSuccess("commons.save_failed", 'error');
this.openMessageSuccess('commons.save_failed', 'error')
}
});
})
},
cancel() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.query();
this.showEdit = true
this.showCancel = false
this.showSave = false
this.show = true
this.query()
},
onSimpleCronChange() {
if (this.formInline.dsCheckIntervalType === 'minute') {
@ -287,9 +338,9 @@ export default {
}
return
}
},
},
};
}
}
}
</script>
<style lang="scss" scoped>

View File

@ -83,7 +83,7 @@
:class="[activeName !== 'eight' ? 'is-center' : 'pad-center']"
>
<div class="min-w600">
<basic-setting v-if="activeName === 'zero'" />
<basic-setting v-if="activeName === 'zero'" :is-plugin-loaded="isPluginLoaded" />
<email-setting v-if="activeName === 'first'" />
<map-setting v-if="activeName === 'ten'" ref="mapSetting" />
<plugin-com v-if="activeName === 'fourth'" ref="DisplaySetting" component-name="LdapSetting" />

View File

@ -188,7 +188,7 @@
slot="__operation"
:label="$t('commons.operating')"
fixed="right"
width="168"
:width="operateWidth"
>
<template slot-scope="scope">
<el-button
@ -245,6 +245,13 @@
type="text"
@click="del(scope.row)"
>{{ $t("commons.delete") }}</el-button>
<el-button
v-if="scope.row.locked"
v-permission="['user:edit']"
class="text-btn"
type="text"
@click="unlock(scope.row)"
>{{ $t("commons.unlock") }}</el-button>
</template>
</el-table-column>
</grid-table>
@ -302,7 +309,8 @@ import {
delUser,
editPassword,
editStatus,
allRoles
allRoles,
unLock
} from '@/api/system/user'
import { mapGetters } from 'vuex'
import filterUser from './filterUser.vue'
@ -358,7 +366,8 @@ export default {
defaultPWD: 'DataEase123..',
canLoadDom: false,
showScroll: false,
resizeForFilter: null
resizeForFilter: null,
operateWidth: 168
}
},
computed: {
@ -534,6 +543,7 @@ export default {
const { currentPage, pageSize } = this.paginationConfig
userLists(currentPage, pageSize, param).then((response) => {
this.data = response.data.listObject
this.dynamicOprtateWidth()
this.paginationConfig.total = response.data.itemCount
})
},
@ -591,6 +601,25 @@ export default {
allRoles().then((res) => {
this.roles = res.data
})
},
unlock(row) {
unLock(row.username).then(res => {
row.locked = false
this.data.forEach(item => {
if (item.username === row.username) {
item.locked = false
}
})
this.dynamicOprtateWidth()
this.$success(this.$t('commons.unlock_success'))
})
},
dynamicOprtateWidth() {
if (this.data && this.data.some(item => item.locked)) {
this.operateWidth = 200
return
}
this.operateWidth = 168
}
}
}