🐛 SSH 配置未启用还可以连接.

This commit is contained in:
lijiahang
2024-03-06 17:58:32 +08:00
parent ba338c15de
commit 201956855f
29 changed files with 177 additions and 57 deletions

View File

@@ -9,7 +9,7 @@
* [常见问题](quickstart/faq.md) * [常见问题](quickstart/faq.md)
* 操作手册 * 操作手册
* [资产管理](operator/asset.md) * [资产管理](operator/asset.md)
* [主机运维](operator/host_ops.md) * [主机运维](operator/host-ops.md)
* [运维审计](operator/host_audit.md) * [运维审计](operator/asset-audit.md)
* [用户管理](operator/user.md) * [用户管理](operator/user.md)
* [系统管理](operator/system.md) * [系统管理](operator/system.md)

View File

@@ -1,5 +1,14 @@
> 版本号严格遵循 Semver 规范。 > 版本号严格遵循 Semver 规范。
## v1.0.2
`2024-03-` `release`
🐞 修复 SSH 配置未启用还可以连接
🐞 修复 主机配置保存后无法修改状态
[如何升级](/about/update.md?id=_v102)
## v1.0.1 ## v1.0.1
`2024-03-06` `release` `2024-03-06` `release`
@@ -11,7 +20,7 @@
🌈 新增 主机连接日志删除/清理 🌈 新增 主机连接日志删除/清理
🌈 新增 用户操作日志日志删除/清理 🌈 新增 用户操作日志日志删除/清理
🌈 新增 用户操作日志日志删除/清理 🌈 新增 用户操作日志日志删除/清理
🔨 优化 用户锁定次数/时间可配置 🔨 优化 用户锁定次数/时间可配置
[如何升级](/about/update.md?id=_v101) [如何升级](/about/update.md?id=_v101)

View File

@@ -75,8 +75,6 @@ public interface ErrorMessage {
String SESSION_ABSENT = "会话不存在"; String SESSION_ABSENT = "会话不存在";
String CONNECT_ERROR = "连接失败";
String PATH_NOT_NORMALIZE = "路径不合法"; String PATH_NOT_NORMALIZE = "路径不合法";
String OPERATE_ERROR = "操作失败"; String OPERATE_ERROR = "操作失败";

View File

@@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -40,8 +41,8 @@ public class AssetAuthorizedDataServiceController {
@IgnoreLog(IgnoreLogMode.RET) @IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/current-host") @GetMapping("/current-host")
@Operation(summary = "查询当前用户已授权的主机") @Operation(summary = "查询当前用户已授权的主机")
public AuthorizedHostWrapperVO getCurrentAuthorizedHostGroup() { public AuthorizedHostWrapperVO getCurrentAuthorizedHost(@RequestParam("type") String type) {
return assetAuthorizedDataService.getUserAuthorizedHostGroup(SecurityUtils.getLoginUserId()); return assetAuthorizedDataService.getUserAuthorizedHost(SecurityUtils.getLoginUserId(), type);
} }
@IgnoreLog(IgnoreLogMode.RET) @IgnoreLog(IgnoreLogMode.RET)

View File

@@ -43,7 +43,7 @@ public enum HostConfigTypeEnum implements GenericsDataDefinition {
return null; return null;
} }
for (HostConfigTypeEnum value : values()) { for (HostConfigTypeEnum value : values()) {
if (value.type.equals(type)) { if (value.type.equalsIgnoreCase(type)) {
return value; return value;
} }
} }

View File

@@ -26,7 +26,7 @@ public enum HostConnectTypeEnum {
return null; return null;
} }
for (HostConnectTypeEnum value : values()) { for (HostConnectTypeEnum value : values()) {
if (value.name().equals(type)) { if (value.name().equalsIgnoreCase(type)) {
return value; return value;
} }
} }

View File

@@ -9,14 +9,18 @@ package com.orion.ops.module.asset.handler.host.terminal.constant;
*/ */
public interface TerminalMessage { public interface TerminalMessage {
String CLOSED_CONNECTION = "closed connection..."; String CONFIG_DISABLED = "SSH configuration has been disabled.";
String AUTHENTICATION_FAILURE = "authentication failure..."; String AUTHENTICATION_FAILURE = "authentication failed. please check the configuration.";
String UNREACHABLE = "remote server unreachable..."; String SERVER_UNREACHABLE = "remote server unreachable. please check the configuration.";
String CONNECTION_TIMEOUT = "connection timeout..."; String CONNECTION_FAILED = "connection failed.";
String FORCED_OFFLINE = "forced offline..."; String CONNECTION_TIMEOUT = "connection timeout.";
String CONNECTION_CLOSED = "connection closed.";
String FORCED_OFFLINE = "forced offline.";
} }

View File

@@ -1,5 +1,6 @@
package com.orion.ops.module.asset.handler.host.terminal.handler; package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.lang.exception.DisabledException;
import com.orion.lang.exception.argument.InvalidArgumentException; import com.orion.lang.exception.argument.InvalidArgumentException;
import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.collect.Maps; import com.orion.lang.utils.collect.Maps;
@@ -17,6 +18,7 @@ import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.ops.module.asset.entity.request.host.HostConnectLogCreateRequest; import com.orion.ops.module.asset.entity.request.host.HostConnectLogCreateRequest;
import com.orion.ops.module.asset.enums.HostConnectStatusEnum; import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
import com.orion.ops.module.asset.enums.HostConnectTypeEnum; import com.orion.ops.module.asset.enums.HostConnectTypeEnum;
import com.orion.ops.module.asset.handler.host.terminal.constant.TerminalMessage;
import com.orion.ops.module.asset.handler.host.terminal.enums.OutputTypeEnum; import com.orion.ops.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalCheckRequest; import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalCheckRequest;
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalCheckResponse; import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalCheckResponse;
@@ -82,9 +84,12 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
log.info("TerminalCheckHandler-handle success userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId); log.info("TerminalCheckHandler-handle success userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {
ex = e; ex = e;
log.error("TerminalCheckHandler-handle error userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e); log.error("TerminalCheckHandler-handle start error userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e);
} catch (DisabledException e) {
ex = Exceptions.runtime(TerminalMessage.CONFIG_DISABLED);
log.error("TerminalCheckHandler-handle disabled error userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
} catch (Exception e) { } catch (Exception e) {
ex = Exceptions.runtime(ErrorMessage.CONNECT_ERROR); ex = Exceptions.runtime(TerminalMessage.CONNECTION_FAILED);
log.error("TerminalCheckHandler-handle exception userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e); log.error("TerminalCheckHandler-handle exception userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e);
} }
// 记录主机日志 // 记录主机日志

View File

@@ -1,7 +1,6 @@
package com.orion.ops.module.asset.handler.host.terminal.handler; package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.lang.exception.AuthenticationException; import com.orion.lang.exception.AuthenticationException;
import com.orion.lang.exception.ConnectionRuntimeException;
import com.orion.lang.exception.TimeoutException; import com.orion.lang.exception.TimeoutException;
import com.orion.lang.exception.argument.InvalidArgumentException; import com.orion.lang.exception.argument.InvalidArgumentException;
import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Exceptions;
@@ -151,9 +150,6 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
if (Exceptions.isCausedBy(e, TimeoutException.class)) { if (Exceptions.isCausedBy(e, TimeoutException.class)) {
// 连接超时 // 连接超时
return TerminalMessage.CONNECTION_TIMEOUT; return TerminalMessage.CONNECTION_TIMEOUT;
} else if (Exceptions.isCausedBy(e, ConnectionRuntimeException.class)) {
// 无法连接
return TerminalMessage.UNREACHABLE;
} else if (Exceptions.isCausedBy(e, AuthenticationException.class)) { } else if (Exceptions.isCausedBy(e, AuthenticationException.class)) {
// 认证失败 // 认证失败
return TerminalMessage.AUTHENTICATION_FAILURE; return TerminalMessage.AUTHENTICATION_FAILURE;
@@ -162,7 +158,7 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
return e.getMessage(); return e.getMessage();
} else { } else {
// 其他错误 // 其他错误
return TerminalMessage.UNREACHABLE; return TerminalMessage.SERVER_UNREACHABLE;
} }
} }

View File

@@ -56,7 +56,7 @@ public abstract class TerminalSession implements ITerminalSession {
.type(OutputTypeEnum.CLOSE.getType()) .type(OutputTypeEnum.CLOSE.getType())
.sessionId(this.sessionId) .sessionId(this.sessionId)
.forceClose(BooleanBit.of(this.forceOffline).getValue()) .forceClose(BooleanBit.of(this.forceOffline).getValue())
.msg(this.forceOffline ? TerminalMessage.FORCED_OFFLINE : TerminalMessage.CLOSED_CONNECTION) .msg(this.forceOffline ? TerminalMessage.FORCED_OFFLINE : TerminalMessage.CONNECTION_CLOSED)
.build(); .build();
WebSockets.sendText(channel, OutputTypeEnum.CLOSE.format(resp)); WebSockets.sendText(channel, OutputTypeEnum.CLOSE.format(resp));
} }

View File

@@ -30,9 +30,10 @@ public interface AssetAuthorizedDataService {
* 查询用户已授权的主机主机 * 查询用户已授权的主机主机
* *
* @param userId userId * @param userId userId
* @param type type
* @return group * @return group
*/ */
AuthorizedHostWrapperVO getUserAuthorizedHostGroup(Long userId); AuthorizedHostWrapperVO getUserAuthorizedHost(Long userId, String type);
/** /**
* 获取用户已授权的主机id 不查询角色 * 获取用户已授权的主机id 不查询角色

View File

@@ -66,4 +66,13 @@ public interface HostConfigService {
*/ */
void initHostConfig(Long hostId); void initHostConfig(Long hostId);
/**
* 获取启用配置的 hostId
*
* @param type type
* @param hostIdList hostIdList
* @return hostId
*/
List<Long> getEnabledConfigHostId(String type, List<Long> hostIdList);
} }

View File

@@ -55,6 +55,9 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
@Resource @Resource
private HostService hostService; private HostService hostService;
@Resource
private HostConfigService hostConfigService;
@Resource @Resource
private HostKeyService hostKeyService; private HostKeyService hostKeyService;
@@ -88,10 +91,10 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
} }
@Override @Override
public AuthorizedHostWrapperVO getUserAuthorizedHostGroup(Long userId) { public AuthorizedHostWrapperVO getUserAuthorizedHost(Long userId, String type) {
if (systemUserApi.isAdminUser(userId)) { if (systemUserApi.isAdminUser(userId)) {
// 管理员查询所有 // 管理员查询所有
return this.buildUserAuthorizedHostGroup(userId, null); return this.buildUserAuthorizedHost(userId, null, type);
} else { } else {
// 其他用户 查询授权的数据 // 其他用户 查询授权的数据
List<Long> authorizedIdList = dataPermissionApi.getUserAuthorizedRelIdList(DataPermissionTypeEnum.HOST_GROUP, userId); List<Long> authorizedIdList = dataPermissionApi.getUserAuthorizedRelIdList(DataPermissionTypeEnum.HOST_GROUP, userId);
@@ -102,7 +105,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
.hostList(Lists.empty()) .hostList(Lists.empty())
.build(); .build();
} }
return this.buildUserAuthorizedHostGroup(userId, authorizedIdList); return this.buildUserAuthorizedHost(userId, authorizedIdList, type);
} }
} }
@@ -173,24 +176,27 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
* *
* @param userId userId * @param userId userId
* @param authorizedGroupIdList authorizedGroupIdList * @param authorizedGroupIdList authorizedGroupIdList
* @param type type
* @return tree * @return tree
*/ */
@SneakyThrows @SneakyThrows
private AuthorizedHostWrapperVO buildUserAuthorizedHostGroup(Long userId, List<Long> authorizedGroupIdList) { private AuthorizedHostWrapperVO buildUserAuthorizedHost(Long userId, List<Long> authorizedGroupIdList, String type) {
final boolean allData = Lists.isEmpty(authorizedGroupIdList); final boolean allData = Lists.isEmpty(authorizedGroupIdList);
AuthorizedHostWrapperVO wrapper = new AuthorizedHostWrapperVO(); AuthorizedHostWrapperVO wrapper = new AuthorizedHostWrapperVO();
// 查询我的收藏 // 查询我的收藏
Future<List<Long>> favoriteResult = favoriteApi.getFavoriteRelIdListAsync(FavoriteTypeEnum.HOST, userId); Future<List<Long>> favoriteResult = favoriteApi.getFavoriteRelIdListAsync(FavoriteTypeEnum.HOST, userId);
// 查询最近连接的主机 // 查询最近连接的主机
Future<List<Long>> latestConnectHostIdList = hostConnectLogService.getLatestConnectHostIdAsync(HostConnectTypeEnum.SSH, userId); Future<List<Long>> latestConnectHostIdList = hostConnectLogService.getLatestConnectHostIdAsync(HostConnectTypeEnum.of(type), userId);
// 查询别名 // 查询主机拓展信息
Future<Map<Long, String>> dataAliasResult = dataExtraApi.getExtraItemValuesByCacheAsync(userId, DataExtraTypeEnum.HOST, DataExtraItems.ALIAS); Future<List<Map<Long, String>>> hostExtraResult = dataExtraApi.getExtraItemsValuesByCacheAsync(userId,
// 查询颜色 DataExtraTypeEnum.HOST,
Future<Map<Long, String>> dataColorResult = dataExtraApi.getExtraItemValuesByCacheAsync(userId, DataExtraTypeEnum.HOST, DataExtraItems.COLOR); Lists.of(DataExtraItems.ALIAS, DataExtraItems.COLOR));
// 查询分组 // 查询分组
List<DataGroupDTO> dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST); List<DataGroupDTO> dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST);
// 查询分组引用 // 查询分组引用
Map<Long, Set<Long>> dataGroupRel = dataGroupRelApi.getGroupRelList(DataGroupTypeEnum.HOST); Map<Long, Set<Long>> dataGroupRel = dataGroupRelApi.getGroupRelList(DataGroupTypeEnum.HOST);
// 查询配置启用的主机
List<Long> enabledConfigHostId = this.getEnabledConfigHostId(allData, dataGroupRel, type);
// 过滤已经授权的分组 // 过滤已经授权的分组
if (!allData) { if (!allData) {
// 构建已授权的分组 // 构建已授权的分组
@@ -209,17 +215,47 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
wrapper.setHostList(this.getAuthorizedHostList(allData, wrapper.setHostList(this.getAuthorizedHostList(allData,
dataGroup, dataGroup,
dataGroupRel, dataGroupRel,
authorizedGroupIdList)); authorizedGroupIdList,
enabledConfigHostId));
// 设置主机拓展信息 // 设置主机拓展信息
this.getAuthorizedHostExtra(wrapper.getHostList(), this.getAuthorizedHostExtra(wrapper.getHostList(),
favoriteResult.get(), favoriteResult.get(),
dataAliasResult.get(), hostExtraResult.get());
dataColorResult.get());
// 设置最近连接的主机 // 设置最近连接的主机
wrapper.setLatestHosts(new LinkedHashSet<>(latestConnectHostIdList.get())); wrapper.setLatestHosts(new LinkedHashSet<>(latestConnectHostIdList.get()));
return wrapper; return wrapper;
} }
/**
* 获取已启用配置的 hostId
*
* @param allData allData
* @param dataGroupRel dataGroupRel
* @param type type
* @return enabledHostIdList
*/
private List<Long> getEnabledConfigHostId(boolean allData,
Map<Long, Set<Long>> dataGroupRel,
String type) {
List<Long> hostIdList = null;
if (!allData) {
// 非全部数据从分组映射中获取
hostIdList = dataGroupRel.values()
.stream()
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
if (hostIdList.isEmpty()) {
return Lists.empty();
}
}
// 查询启用配置的主机
List<Long> enabledConfigHostId = hostConfigService.getEnabledConfigHostId(type, hostIdList);
// 从分组引用中移除
dataGroupRel.forEach((k, v) -> v.removeIf(s -> !enabledConfigHostId.contains(s)));
return enabledConfigHostId;
}
/** /**
* 构建主机分组树 * 构建主机分组树
* *
@@ -265,14 +301,19 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
* @param dataGroup dataGroup * @param dataGroup dataGroup
* @param dataGroupRel dataGroupRel * @param dataGroupRel dataGroupRel
* @param authorizedGroupIdList authorizedGroupIdList * @param authorizedGroupIdList authorizedGroupIdList
* @param enabledConfigHostId enabledConfigHostId
* @return hosts * @return hosts
*/ */
private List<HostVO> getAuthorizedHostList(boolean allData, private List<HostVO> getAuthorizedHostList(boolean allData,
List<DataGroupDTO> dataGroup, List<DataGroupDTO> dataGroup,
Map<Long, Set<Long>> dataGroupRel, Map<Long, Set<Long>> dataGroupRel,
List<Long> authorizedGroupIdList) { List<Long> authorizedGroupIdList,
List<Long> enabledConfigHostId) {
// 查询主机列表 // 查询主机列表
List<HostVO> hosts = hostService.getHostListByCache(); List<HostVO> hosts = hostService.getHostListByCache()
.stream()
.filter(s -> enabledConfigHostId.contains(s.getId()))
.collect(Collectors.toList());
// 全部数据直接返回 // 全部数据直接返回
if (allData) { if (allData) {
return hosts; return hosts;
@@ -296,15 +337,13 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
/** /**
* 设置授权主机的额外参数 * 设置授权主机的额外参数
* *
* @param hosts hosts * @param hosts hosts
* @param favorite favorite * @param favorite favorite
* @param aliasMap aliasMap * @param extraList extraList
* @param colorMap colorMap
*/ */
private void getAuthorizedHostExtra(List<HostVO> hosts, private void getAuthorizedHostExtra(List<HostVO> hosts,
List<Long> favorite, List<Long> favorite,
Map<Long, String> aliasMap, List<Map<Long, String>> extraList) {
Map<Long, String> colorMap) {
if (Lists.isEmpty(hosts)) { if (Lists.isEmpty(hosts)) {
return; return;
} }
@@ -321,6 +360,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
hosts.get(i).setTags(tags.get(i)); hosts.get(i).setTags(tags.get(i));
} }
// 设置主机别名 // 设置主机别名
Map<Long, String> aliasMap = extraList.get(0);
if (!Maps.isEmpty(aliasMap)) { if (!Maps.isEmpty(aliasMap)) {
hosts.forEach(s -> { hosts.forEach(s -> {
String alias = aliasMap.get(s.getId()); String alias = aliasMap.get(s.getId());
@@ -330,6 +370,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
}); });
} }
// 设置主机颜色 // 设置主机颜色
Map<Long, String> colorMap = extraList.get(1);
if (!Maps.isEmpty(colorMap)) { if (!Maps.isEmpty(colorMap)) {
hosts.forEach(s -> { hosts.forEach(s -> {
HostColorExtraModel color = JSON.parseObject(colorMap.get(s.getId()), HostColorExtraModel.class); HostColorExtraModel color = JSON.parseObject(colorMap.get(s.getId()), HostColorExtraModel.class);

View File

@@ -1,8 +1,10 @@
package com.orion.ops.module.asset.service.impl; package com.orion.ops.module.asset.service.impl;
import com.orion.lang.utils.Exceptions;
import com.orion.ops.framework.biz.operator.log.core.utils.OperatorLogs; import com.orion.ops.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.ops.framework.common.constant.Const; import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.constant.ErrorMessage; import com.orion.ops.framework.common.constant.ErrorMessage;
import com.orion.ops.framework.common.enums.BooleanBit;
import com.orion.ops.framework.common.enums.EnableStatus; import com.orion.ops.framework.common.enums.EnableStatus;
import com.orion.ops.framework.common.handler.data.model.GenericsDataModel; import com.orion.ops.framework.common.handler.data.model.GenericsDataModel;
import com.orion.ops.framework.common.handler.data.strategy.MapDataStrategy; import com.orion.ops.framework.common.handler.data.strategy.MapDataStrategy;
@@ -21,10 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Arrays; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -66,6 +65,10 @@ public class HostConfigServiceImpl implements HostConfigService {
if (config == null) { if (config == null) {
return null; return null;
} }
// 检查配置状态
if (!BooleanBit.toBoolean(config.getStatus())) {
throw Exceptions.disabled();
}
return type.parse(config.getConfig()); return type.parse(config.getConfig());
} }
@@ -145,6 +148,7 @@ public class HostConfigServiceImpl implements HostConfigService {
update.setId(config.getId()); update.setId(config.getId());
update.setStatus(status); update.setStatus(status);
update.setVersion(version); update.setVersion(version);
update.setUpdateTime(new Date());
int effect = hostConfigDAO.updateById(update); int effect = hostConfigDAO.updateById(update);
Valid.version(effect); Valid.version(effect);
return update.getVersion(); return update.getVersion();
@@ -167,6 +171,20 @@ public class HostConfigServiceImpl implements HostConfigService {
hostConfigDAO.insertBatch(configs); hostConfigDAO.insertBatch(configs);
} }
@Override
public List<Long> getEnabledConfigHostId(String type, List<Long> hostIdList) {
return hostConfigDAO.of()
.createValidateWrapper()
.select(HostConfigDO::getHostId)
.eq(HostConfigDO::getType, type)
.eq(HostConfigDO::getStatus, BooleanBit.TRUE.getValue())
.in(HostConfigDO::getHostId, hostIdList)
.then()
.stream()
.map(HostConfigDO::getHostId)
.collect(Collectors.toList());
}
/** /**
* 通过类型获取配置 * 通过类型获取配置
* *

View File

@@ -101,6 +101,16 @@ public interface DataExtraApi {
*/ */
Future<Map<Long, String>> getExtraItemValuesByCacheAsync(Long userId, DataExtraTypeEnum type, String item); Future<Map<Long, String>> getExtraItemValuesByCacheAsync(Long userId, DataExtraTypeEnum type, String item);
/**
* 异步查询额外配置项 (查询缓存)
*
* @param userId userId
* @param type type
* @param items items
* @return value
*/
Future<List<Map<Long, String>>> getExtraItemsValuesByCacheAsync(Long userId, DataExtraTypeEnum type, List<String> items);
/** /**
* 查询额外配置 * 查询额外配置
* *

View File

@@ -102,6 +102,13 @@ public class DataExtraApiImpl implements DataExtraApi {
return CompletableFuture.completedFuture(this.getExtraItemValuesByCache(userId, type, item)); return CompletableFuture.completedFuture(this.getExtraItemValuesByCache(userId, type, item));
} }
@Override
public Future<List<Map<Long, String>>> getExtraItemsValuesByCacheAsync(Long userId, DataExtraTypeEnum type, List<String> items) {
Valid.allNotNull(userId, type);
Valid.notEmpty(items);
return CompletableFuture.completedFuture(dataExtraService.getExtraItemsValuesByCache(userId, type.name(), items));
}
@Override @Override
public DataExtraDTO getExtraItem(DataExtraQueryDTO dto, DataExtraTypeEnum type) { public DataExtraDTO getExtraItem(DataExtraQueryDTO dto, DataExtraTypeEnum type) {
Valid.allNotNull(dto.getUserId(), dto.getRelId(), dto.getItem()); Valid.allNotNull(dto.getUserId(), dto.getRelId(), dto.getItem());

View File

@@ -85,6 +85,16 @@ public interface DataExtraService {
*/ */
Map<Long, String> getExtraItemValuesByCache(Long userId, String type, String item); Map<Long, String> getExtraItemValuesByCache(Long userId, String type, String item);
/**
* 查询额外配置项 (查询缓存)
*
* @param userId userId
* @param type type
* @param items items
* @return [relId:value, relId:value]
*/
List<Map<Long, String>> getExtraItemsValuesByCache(Long userId, String type, List<String> items);
/** /**
* 查询额外配置 * 查询额外配置
* *

View File

@@ -170,6 +170,13 @@ public class DataExtraServiceImpl implements DataExtraService {
return Maps.map(entities, Long::valueOf, Function.identity()); return Maps.map(entities, Long::valueOf, Function.identity());
} }
@Override
public List<Map<Long, String>> getExtraItemsValuesByCache(Long userId, String type, List<String> items) {
return items.stream()
.map(s -> this.getExtraItemValuesByCache(userId, type, s))
.collect(Collectors.toList());
}
@Override @Override
public DataExtraDO getExtraItem(DataExtraQueryRequest request) { public DataExtraDO getExtraItem(DataExtraQueryRequest request) {
return dataExtraDAO.of() return dataExtraDAO.of()

View File

@@ -17,8 +17,8 @@ export interface AuthorizedHostQueryResponse {
/** /**
* 查询当前用户已授权的主机 * 查询当前用户已授权的主机
*/ */
export function getCurrentAuthorizedHost() { export function getCurrentAuthorizedHost(type: string) {
return axios.get<AuthorizedHostQueryResponse>('/asset/authorized-data/current-host'); return axios.get<AuthorizedHostQueryResponse>('/asset/authorized-data/current-host', { params: { type } });
} }
/** /**

View File

@@ -128,7 +128,7 @@ export default defineStore('terminal', {
if (this.hosts.hostList?.length) { if (this.hosts.hostList?.length) {
return; return;
} }
const { data } = await getCurrentAuthorizedHost(); const { data } = await getCurrentAuthorizedHost('ssh');
Object.keys(data).forEach(k => { Object.keys(data).forEach(k => {
this.hosts[k as keyof AuthorizedHostQueryResponse] = data[k as keyof AuthorizedHostQueryResponse] as any; this.hosts[k as keyof AuthorizedHostQueryResponse] = data[k as keyof AuthorizedHostQueryResponse] as any;
}); });

View File

@@ -45,7 +45,9 @@
unchecked-text="使用原密码" /> unchecked-text="使用原密码" />
</a-form-item> </a-form-item>
<!-- 秘钥id --> <!-- 秘钥id -->
<a-form-item field="keyId" label="主机秘钥"> <a-form-item field="keyId"
label="主机秘钥"
extra="密码和秘钥二选一 优先使用秘钥">
<host-key-selector v-model="formModel.keyId" /> <host-key-selector v-model="formModel.keyId" />
</a-form-item> </a-form-item>
</a-form> </a-form>

View File

@@ -260,7 +260,7 @@
setLoading(false); setLoading(false);
Message.success('修改成功'); Message.success('修改成功');
// 回调 props // 回调 props
emits('submitted', { ...props.content, config: { ...formModel.value } }); emits('submitted', { ...props.content, ...config, config: { ...formModel.value } });
} catch (e) { } catch (e) {
} finally { } finally {
setLoading(false); setLoading(false);

View File

@@ -17,7 +17,7 @@
<!-- 主机列表 --> <!-- 主机列表 -->
<host-list-view class="host-list" <host-list-view class="host-list"
:hostList="hostList" :hostList="hostList"
empty-value="当前分组内无授权主机!" /> empty-value="当前分组内无授权主机/主机未启用 SSH 配置!" />
</div> </div>
</template> </template>

View File

@@ -10,7 +10,7 @@
<!-- 列表视图 --> <!-- 列表视图 -->
<host-list-view v-if="NewConnectionType.LIST === newConnectionType" <host-list-view v-if="NewConnectionType.LIST === newConnectionType"
:hostList="hostList" :hostList="hostList"
empty-value="无授权主机!" /> empty-value="无授权主机/主机未启用 SSH 配置!" />
<!-- 我的收藏 --> <!-- 我的收藏 -->
<host-list-view v-if="NewConnectionType.FAVORITE === newConnectionType" <host-list-view v-if="NewConnectionType.FAVORITE === newConnectionType"
class="list-view-container" class="list-view-container"

View File

@@ -46,7 +46,7 @@
</div> </div>
<!-- 已关闭-右侧操作 --> <!-- 已关闭-右侧操作 -->
<div v-if="isClose" class="sftp-table-header-right"> <div v-if="isClose" class="sftp-table-header-right">
<span class="close-message">{{ closeMessage }}</span> <span class="close-message" :title="closeMessage">{{ closeMessage }}</span>
</div> </div>
<!-- 路径编辑模式-右侧操作 --> <!-- 路径编辑模式-右侧操作 -->
<a-space v-else-if="pathEditable" class="sftp-table-header-right"> <a-space v-else-if="pathEditable" class="sftp-table-header-right">

View File

@@ -190,10 +190,10 @@
// 关闭回调 // 关闭回调
const onClose = (forceClose: string, msg: string) => { const onClose = (forceClose: string, msg: string) => {
console.log(forceClose);
console.log(msg);
closed.value = true; closed.value = true;
closeMessage.value = msg; closeMessage.value = msg;
setTableLoading(false);
setEditorLoading(false);
}; };
// 接收列表回调 // 接收列表回调

View File

@@ -47,6 +47,7 @@ export default class TerminalOutputProcessor implements ITerminalOutputProcessor
}); });
} else { } else {
// 未成功提示错误信息 // 未成功提示错误信息
session.resolver?.onClose('0', msg);
Message.error(msg || '建立 SFTP 失败'); Message.error(msg || '建立 SFTP 失败');
} }
} }
@@ -75,6 +76,7 @@ export default class TerminalOutputProcessor implements ITerminalOutputProcessor
session.connect(); session.connect();
} else { } else {
// 未成功提示错误信息 // 未成功提示错误信息
session.resolver?.onClose('0', msg);
Message.error(msg || '打开 SFTP 失败'); Message.error(msg || '打开 SFTP 失败');
} }
} }