修改主机配置策略
This commit is contained in:
@@ -21,7 +21,9 @@ public interface ErrorMessage {
|
||||
|
||||
String DATA_ABSENT = "数据不存在";
|
||||
|
||||
String KEY_ABSENT = "秘钥不存在";
|
||||
String KEY_ABSENT = "主机秘钥不存在";
|
||||
|
||||
String IDENTITY_ABSENT = "主机身份不存在";
|
||||
|
||||
String CONFIG_ABSENT = "配置不存在";
|
||||
|
||||
@@ -51,4 +53,8 @@ public interface ErrorMessage {
|
||||
|
||||
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
|
||||
|
||||
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";
|
||||
|
||||
String PASSWORD_MISSING = "请输入密码";
|
||||
|
||||
}
|
||||
|
||||
@@ -93,7 +93,9 @@
|
||||
// 渲染表单
|
||||
const renderForm = (record: any) => {
|
||||
Object.keys(formModel).forEach(k => {
|
||||
formModel[k] = record[k];
|
||||
if (record.hasOwnProperty(k)) {
|
||||
formModel[k] = record[k];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -97,7 +97,9 @@
|
||||
// 渲染表单
|
||||
const renderForm = (record: any) => {
|
||||
Object.keys(formModel).forEach(k => {
|
||||
formModel[k] = record[k];
|
||||
if (record.hasOwnProperty(k)) {
|
||||
formModel[k] = record[k];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
selectedKeys.value = [];
|
||||
// 重新加载数据
|
||||
await fetchTableData();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -157,6 +158,7 @@
|
||||
Message.success('删除成功');
|
||||
// 重新加载数据
|
||||
await fetchTableData();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -185,6 +187,7 @@
|
||||
pagination.total = data.total;
|
||||
pagination.current = request.page;
|
||||
pagination.pageSize = request.limit;
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class HostKeyController {
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/list")
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询主机秘钥")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host-key:query')")
|
||||
public List<HostKeyVO> getHostKeyList() {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.orion.ops.module.asset.enums;
|
||||
|
||||
/**
|
||||
* 主机验证类型
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/9/21 19:01
|
||||
*/
|
||||
public enum HostAuthTypeEnum {
|
||||
|
||||
/**
|
||||
* 密码验证
|
||||
*/
|
||||
PASSWORD,
|
||||
|
||||
/**
|
||||
* 秘钥验证
|
||||
*/
|
||||
KEY,
|
||||
|
||||
/**
|
||||
* 身份验证
|
||||
*/
|
||||
IDENTITY,
|
||||
|
||||
;
|
||||
|
||||
public static HostAuthTypeEnum of(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
for (HostAuthTypeEnum value : values()) {
|
||||
if (value.name().equals(type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
|
||||
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
||||
import com.orion.ops.module.asset.handler.host.config.strategy.HostConfigStrategy;
|
||||
import com.orion.ops.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
|
||||
import com.orion.spring.SpringHolder;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
@@ -20,13 +21,13 @@ public enum HostConfigTypeEnum {
|
||||
/**
|
||||
* SSH 配置
|
||||
*/
|
||||
SSH(HostSshConfigModel.class, new HostSshConfigStrategy(), BooleanBit.TRUE.getValue()),
|
||||
SSH(HostSshConfigModel.class, HostSshConfigStrategy.class, BooleanBit.TRUE.getValue()),
|
||||
|
||||
;
|
||||
|
||||
private final Class<? extends HostConfigModel> type;
|
||||
|
||||
private final HostConfigStrategy<?> strategy;
|
||||
private final Class<? extends HostConfigStrategy<? extends HostConfigModel>> strategy;
|
||||
|
||||
private final Integer defaultStatus;
|
||||
|
||||
@@ -48,7 +49,7 @@ public enum HostConfigTypeEnum {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <Config extends HostConfigModel, T extends HostConfigStrategy<Config>> T getStrategy() {
|
||||
return (T) strategy;
|
||||
return (T) SpringHolder.getBean(strategy);
|
||||
}
|
||||
|
||||
public Integer getDefaultStatus() {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package com.orion.ops.module.asset.handler.host.config.model;
|
||||
|
||||
import com.orion.ops.framework.common.security.UpdatePasswordAction;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Range;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 主机 SSH 配置
|
||||
@@ -21,36 +24,54 @@ import javax.validation.constraints.NotNull;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "HostSftpConfig", description = "主机 SSH 配置")
|
||||
public class HostSshConfigModel implements HostConfigModel {
|
||||
public class HostSshConfigModel implements HostConfigModel, UpdatePasswordAction {
|
||||
|
||||
@NotNull
|
||||
@Range(min = 1, max = 65535)
|
||||
@Schema(description = "ssh 端口")
|
||||
private Integer port;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 128)
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
private String authType;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "身份id")
|
||||
private Long identityId;
|
||||
|
||||
@Schema(description = "秘钥id")
|
||||
private Long keyId;
|
||||
|
||||
@NotNull
|
||||
@Range(min = 0, max = 100000)
|
||||
@Schema(description = "连接超时时间")
|
||||
private Integer connectTimeout;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "SSH输出编码")
|
||||
private String charset;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "文件名称编码")
|
||||
private String fileNameCharset;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "文件内容编码")
|
||||
private String fileContentCharset;
|
||||
|
||||
@Schema(description = "是否使用新密码 仅参数")
|
||||
private Boolean useNewPassword;
|
||||
|
||||
@Schema(description = "是否已设置密码 仅返回")
|
||||
private Boolean hasPassword;
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,20 @@ public interface HostConfigStrategy<Config extends HostConfigModel> {
|
||||
*/
|
||||
void updateFill(Config before, Config after);
|
||||
|
||||
/**
|
||||
* 预校验参数
|
||||
*
|
||||
* @param config config
|
||||
*/
|
||||
void preValidConfig(Config config);
|
||||
|
||||
/**
|
||||
* 校验参数
|
||||
*
|
||||
* @param config config
|
||||
*/
|
||||
void validConfig(Config config);
|
||||
|
||||
/**
|
||||
* 转为视图配置
|
||||
*
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
package com.orion.ops.module.asset.handler.host.config.strategy;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orion.lang.utils.Booleans;
|
||||
import com.orion.lang.utils.Charsets;
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.ops.framework.common.constant.Const;
|
||||
import com.orion.ops.framework.common.utils.CryptoUtils;
|
||||
import com.orion.ops.framework.common.constant.ErrorMessage;
|
||||
import com.orion.ops.framework.common.security.PasswordModifier;
|
||||
import com.orion.ops.framework.common.utils.Valid;
|
||||
import com.orion.ops.module.asset.dao.HostIdentityDAO;
|
||||
import com.orion.ops.module.asset.dao.HostKeyDAO;
|
||||
import com.orion.ops.module.asset.enums.HostAuthTypeEnum;
|
||||
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -15,8 +25,15 @@ import java.util.Map;
|
||||
* @version 1.0.0
|
||||
* @since 2023/9/19 14:26
|
||||
*/
|
||||
@Component
|
||||
public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigModel> {
|
||||
|
||||
@Resource
|
||||
private HostKeyDAO hostKeyDAO;
|
||||
|
||||
@Resource
|
||||
private HostIdentityDAO hostIdentityDAO;
|
||||
|
||||
private static final int SSH_PORT = 22;
|
||||
|
||||
@Override
|
||||
@@ -30,10 +47,38 @@ public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigMo
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preValidConfig(HostSshConfigModel config) {
|
||||
// 验证认证类型
|
||||
Valid.valid(HostAuthTypeEnum::of, config.getAuthType());
|
||||
// 验证编码格式
|
||||
this.validCharset(config.getCharset());
|
||||
this.validCharset(config.getFileNameCharset());
|
||||
this.validCharset(config.getFileContentCharset());
|
||||
// 检查主机秘钥是否存在
|
||||
Long keyId = config.getKeyId();
|
||||
if (keyId != null) {
|
||||
Valid.notNull(hostKeyDAO.selectById(keyId), ErrorMessage.KEY_ABSENT);
|
||||
}
|
||||
// 检查主机身份是否存在
|
||||
Long identityId = config.getIdentityId();
|
||||
if (identityId != null) {
|
||||
Valid.notNull(hostIdentityDAO.selectById(identityId), ErrorMessage.IDENTITY_ABSENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validConfig(HostSshConfigModel config) {
|
||||
// 验证填充后的参数
|
||||
Valid.valid(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(HostSshConfigModel before, HostSshConfigModel after) {
|
||||
// 加密密码
|
||||
this.checkEncryptPassword(after);
|
||||
this.checkEncryptPassword(before, after);
|
||||
after.setHasPassword(null);
|
||||
after.setUseNewPassword(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,17 +87,42 @@ public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigMo
|
||||
return null;
|
||||
}
|
||||
HostSshConfigModel model = JSON.parseObject(config, HostSshConfigModel.class);
|
||||
model.setHasPassword(Strings.isNotBlank(model.getPassword()));
|
||||
model.setPassword(null);
|
||||
return JSON.parseObject(JSON.toJSONString(model));
|
||||
}
|
||||
|
||||
private void checkEncryptPassword(HostSshConfigModel config) {
|
||||
String password = config.getPassword();
|
||||
if (Strings.isBlank(password)) {
|
||||
/**
|
||||
* 检查加密密码
|
||||
*
|
||||
* @param before before
|
||||
* @param after after
|
||||
*/
|
||||
private void checkEncryptPassword(HostSshConfigModel before, HostSshConfigModel after) {
|
||||
// 非密码认证则直接赋值
|
||||
if (!HostAuthTypeEnum.PASSWORD.name().equals(after.getAuthType())) {
|
||||
after.setPassword(before.getPassword());
|
||||
return;
|
||||
}
|
||||
// 加密密码
|
||||
config.setPassword(CryptoUtils.encryptAsString(password));
|
||||
// 检查是否无密码
|
||||
if (Booleans.isTrue(after.getUseNewPassword()) && Strings.isBlank(after.getPassword())) {
|
||||
throw Exceptions.argument(ErrorMessage.PASSWORD_MISSING);
|
||||
}
|
||||
// 设置密码
|
||||
String newPassword = PasswordModifier.getEncryptNewPassword(after);
|
||||
if (newPassword == null) {
|
||||
newPassword = before.getPassword();
|
||||
}
|
||||
after.setPassword(newPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查编码格式
|
||||
*
|
||||
* @param charset charset
|
||||
*/
|
||||
private void validCharset(String charset) {
|
||||
Valid.isTrue(Charsets.isSupported(charset), ErrorMessage.UNSUPPORTED_CHARSET, charset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateStatusRequ
|
||||
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
|
||||
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
||||
import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
|
||||
import com.orion.ops.module.asset.handler.host.config.strategy.HostConfigStrategy;
|
||||
import com.orion.ops.module.asset.service.HostConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -91,11 +92,14 @@ public class HostConfigServiceImpl implements HostConfigService {
|
||||
HostConfigModel config = JSON.parseObject(request.getConfig(), type.getType());
|
||||
// 检查版本
|
||||
Valid.eq(record.getVersion(), request.getVersion(), ErrorMessage.DATA_MODIFIED);
|
||||
// 填充
|
||||
HostConfigStrategy<HostConfigModel> strategy = type.getStrategy();
|
||||
// 预校验参数
|
||||
strategy.preValidConfig(config);
|
||||
// 更新填充
|
||||
HostConfigModel beforeConfig = JSON.parseObject(record.getConfig(), type.getType());
|
||||
type.getStrategy().updateFill(beforeConfig, config);
|
||||
strategy.updateFill(beforeConfig, config);
|
||||
// 检查参数
|
||||
Valid.valid(config);
|
||||
strategy.validConfig(config);
|
||||
// 修改配置
|
||||
HostConfigDO update = new HostConfigDO();
|
||||
update.setId(id);
|
||||
|
||||
Reference in New Issue
Block a user