修改主机配置策略

This commit is contained in:
lijiahang
2023-09-22 11:48:52 +08:00
parent f5f9cff4d4
commit 9398f0f4fd
11 changed files with 183 additions and 19 deletions

View File

@@ -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 = "请输入密码";
}

View File

@@ -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];
}
});
};

View File

@@ -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];
}
});
};

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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() {

View File

@@ -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;
}

View File

@@ -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);
/**
* 转为视图配置
*

View File

@@ -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);
}
}

View File

@@ -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);