增加密码加密
This commit is contained in:
parent
3d454a0802
commit
9d42dd1ba3
@ -0,0 +1,75 @@
|
|||||||
|
package com.qqchen.deploy.backend.deploy.integration.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.framework.util.SensitiveDataEncryptor;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部系统集成基类
|
||||||
|
* 提供统一的密码解密功能
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-11-11
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class BaseExternalSystemIntegration {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected SensitiveDataEncryptor encryptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密外部系统的敏感数据(密码和Token)
|
||||||
|
* 创建一个新对象,不影响原对象
|
||||||
|
*
|
||||||
|
* @param system 原始的外部系统对象(包含加密的密码)
|
||||||
|
* @return 解密后的外部系统对象
|
||||||
|
*/
|
||||||
|
protected ExternalSystem decryptSystem(ExternalSystem system) {
|
||||||
|
if (system == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新对象,避免修改原对象
|
||||||
|
ExternalSystem decrypted = new ExternalSystem();
|
||||||
|
|
||||||
|
// 复制所有属性
|
||||||
|
decrypted.setId(system.getId());
|
||||||
|
decrypted.setName(system.getName());
|
||||||
|
decrypted.setType(system.getType());
|
||||||
|
decrypted.setUrl(system.getUrl());
|
||||||
|
decrypted.setAuthType(system.getAuthType());
|
||||||
|
decrypted.setUsername(system.getUsername());
|
||||||
|
decrypted.setEnabled(system.getEnabled());
|
||||||
|
decrypted.setConfig(system.getConfig());
|
||||||
|
decrypted.setRemark(system.getRemark());
|
||||||
|
decrypted.setSort(system.getSort());
|
||||||
|
|
||||||
|
// 解密密码
|
||||||
|
if (StringUtils.isNotBlank(system.getPassword())) {
|
||||||
|
try {
|
||||||
|
String decryptedPassword = encryptor.decrypt(system.getPassword());
|
||||||
|
decrypted.setPassword(decryptedPassword);
|
||||||
|
log.debug("外部系统密码已解密: systemId={}, systemName={}", system.getId(), system.getName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解密密码失败,使用原值: systemId={}, error={}", system.getId(), e.getMessage());
|
||||||
|
decrypted.setPassword(system.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密Token
|
||||||
|
if (StringUtils.isNotBlank(system.getToken())) {
|
||||||
|
try {
|
||||||
|
String decryptedToken = encryptor.decrypt(system.getToken());
|
||||||
|
decrypted.setToken(decryptedToken);
|
||||||
|
log.debug("外部系统Token已解密: systemId={}, systemName={}", system.getId(), system.getName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解密Token失败,使用原值: systemId={}, error={}", system.getId(), e.getMessage());
|
||||||
|
decrypted.setToken(system.getToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,12 +27,13 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
public class GitServiceIntegrationImpl extends BaseExternalSystemIntegration implements IGitServiceIntegration {
|
||||||
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testConnection(ExternalSystem system) {
|
public boolean testConnection(ExternalSystem system) {
|
||||||
|
system = decryptSystem(system);
|
||||||
try {
|
try {
|
||||||
String url = system.getUrl() + "/api/v4/version";
|
String url = system.getUrl() + "/api/v4/version";
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
@ -54,6 +55,7 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GitGroupResponse> groups(ExternalSystem system) {
|
public List<GitGroupResponse> groups(ExternalSystem system) {
|
||||||
|
system = decryptSystem(system);
|
||||||
try {
|
try {
|
||||||
String url = String.format("%s/api/v4/groups?per_page=100", system.getUrl());
|
String url = String.format("%s/api/v4/groups?per_page=100", system.getUrl());
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
@ -76,6 +78,7 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GitProjectResponse> projects(ExternalSystem system) {
|
public List<GitProjectResponse> projects(ExternalSystem system) {
|
||||||
|
system = decryptSystem(system);
|
||||||
try {
|
try {
|
||||||
String url = String.format("%s/api/v4/projects", system.getUrl());
|
String url = String.format("%s/api/v4/projects", system.getUrl());
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
@ -98,6 +101,7 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GitProjectResponse> projectsByGroup(ExternalSystem system, Long groupId) {
|
public List<GitProjectResponse> projectsByGroup(ExternalSystem system, Long groupId) {
|
||||||
|
system = decryptSystem(system);
|
||||||
try {
|
try {
|
||||||
String url = String.format("%s/api/v4/groups/%d/projects?per_page=100", system.getUrl(), groupId);
|
String url = String.format("%s/api/v4/groups/%d/projects?per_page=100", system.getUrl(), groupId);
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
@ -120,6 +124,7 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GitBranchResponse> branches(ExternalSystem system, Long projectId) {
|
public List<GitBranchResponse> branches(ExternalSystem system, Long projectId) {
|
||||||
|
system = decryptSystem(system);
|
||||||
try {
|
try {
|
||||||
String url = String.format("%s/api/v4/projects/%d/repository/branches?per_page=100", system.getUrl(), projectId);
|
String url = String.format("%s/api/v4/projects/%d/repository/branches?per_page=100", system.getUrl(), projectId);
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
|
|||||||
@ -51,7 +51,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration {
|
public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration implements IJenkinsServiceIntegration {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IExternalSystemRepository systemRepository;
|
private IExternalSystemRepository systemRepository;
|
||||||
@ -60,16 +60,12 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testConnection(ExternalSystem system) {
|
public boolean testConnection(ExternalSystem system) {
|
||||||
|
// 解密系统信息
|
||||||
|
system = decryptSystem(system);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String url = system.getUrl() + "/api/json";
|
String url = system.getUrl() + "/api/json";
|
||||||
|
|
||||||
// 详细日志:检查认证信息
|
|
||||||
log.info("===== Jenkins连接测试调试信息 =====");
|
|
||||||
log.info("URL: {}", url);
|
|
||||||
log.info("认证类型: {}", system.getAuthType());
|
|
||||||
log.info("用户名: {}", system.getUsername());
|
|
||||||
log.info("密码是否为空: {}", system.getPassword() == null || system.getPassword().isEmpty());
|
|
||||||
|
|
||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
|
|
||||||
// 打印实际发送的请求头
|
// 打印实际发送的请求头
|
||||||
@ -137,6 +133,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JenkinsCrumbIssuerResponse getJenkinsCrumbIssue(ExternalSystem externalSystem) {
|
public JenkinsCrumbIssuerResponse getJenkinsCrumbIssue(ExternalSystem externalSystem) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
String url = externalSystem.getUrl() + "/crumbIssuer/api/json";
|
String url = externalSystem.getUrl() + "/crumbIssuer/api/json";
|
||||||
HttpHeaders headers = createHeaders(externalSystem);
|
HttpHeaders headers = createHeaders(externalSystem);
|
||||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
@ -145,6 +142,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String buildWithParameters(ExternalSystem externalSystem, String jobName, Map<String, String> parameters) {
|
public String buildWithParameters(ExternalSystem externalSystem, String jobName, Map<String, String> parameters) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
try {
|
try {
|
||||||
// 如果参数中包含PIPELINE_SCRIPT,确保Job配置中有该参数
|
// 如果参数中包含PIPELINE_SCRIPT,确保Job配置中有该参数
|
||||||
if (parameters.containsKey("PIPELINE_SCRIPT")) {
|
if (parameters.containsKey("PIPELINE_SCRIPT")) {
|
||||||
@ -375,6 +373,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JenkinsQueueBuildInfoResponse getQueuedBuildInfo(ExternalSystem externalSystem, String queueId) {
|
public JenkinsQueueBuildInfoResponse getQueuedBuildInfo(ExternalSystem externalSystem, String queueId) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
String queueUrl = String.format("%s/queue/item/%s/api/json", externalSystem.getUrl().trim(), queueId);
|
String queueUrl = String.format("%s/queue/item/%s/api/json", externalSystem.getUrl().trim(), queueId);
|
||||||
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(queueUrl, HttpMethod.GET, createHttpEntity(externalSystem), new ParameterizedTypeReference<>() {
|
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(queueUrl, HttpMethod.GET, createHttpEntity(externalSystem), new ParameterizedTypeReference<>() {
|
||||||
});
|
});
|
||||||
@ -405,6 +404,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JenkinsBuildStatus getBuildStatus(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
public JenkinsBuildStatus getBuildStatus(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
try {
|
try {
|
||||||
String url = String.format("%s/job/%s/%d/api/json", externalSystem.getUrl().trim(), jobName, buildNumber);
|
String url = String.format("%s/job/%s/%d/api/json", externalSystem.getUrl().trim(), jobName, buildNumber);
|
||||||
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
|
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
|
||||||
@ -435,6 +435,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JenkinsBuildResponse getBuildDetails(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
public JenkinsBuildResponse getBuildDetails(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
try {
|
try {
|
||||||
// 构建 tree 参数,只获取我们需要的字段
|
// 构建 tree 参数,只获取我们需要的字段
|
||||||
String treeQuery = "number,url,result,duration,timestamp,building," +
|
String treeQuery = "number,url,result,duration,timestamp,building," +
|
||||||
@ -562,9 +563,10 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
* @return 视图列表
|
* @return 视图列表
|
||||||
*/
|
*/
|
||||||
public List<JenkinsViewResponse> listViews(ExternalSystem externalSystem) {
|
public List<JenkinsViewResponse> listViews(ExternalSystem externalSystem) {
|
||||||
|
final ExternalSystem decryptedSystem = decryptSystem(externalSystem);
|
||||||
String treeQuery = "views[name,url,description,_class]";
|
String treeQuery = "views[name,url,description,_class]";
|
||||||
List<JenkinsViewResponse> views = callJenkinsApi(
|
List<JenkinsViewResponse> views = callJenkinsApi(
|
||||||
externalSystem,
|
decryptedSystem,
|
||||||
"/api/json",
|
"/api/json",
|
||||||
treeQuery,
|
treeQuery,
|
||||||
"views",
|
"views",
|
||||||
@ -572,6 +574,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 过滤和清洗数据
|
// 过滤和清洗数据
|
||||||
|
final String baseUrl = StringUtils.removeEnd(decryptedSystem.getUrl(), "/");
|
||||||
return views.stream()
|
return views.stream()
|
||||||
.filter(view -> !"all".equalsIgnoreCase(view.getName()))
|
.filter(view -> !"all".equalsIgnoreCase(view.getName()))
|
||||||
.peek(view -> {
|
.peek(view -> {
|
||||||
@ -581,7 +584,6 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
}
|
}
|
||||||
// 转换URL为相对路径
|
// 转换URL为相对路径
|
||||||
if (view.getUrl() != null) {
|
if (view.getUrl() != null) {
|
||||||
String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
|
|
||||||
view.setUrl(view.getUrl().replace(baseUrl, ""));
|
view.setUrl(view.getUrl().replace(baseUrl, ""));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -596,6 +598,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
* @return 任务列表
|
* @return 任务列表
|
||||||
*/
|
*/
|
||||||
public List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName) {
|
public List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
// 只查询必要的字段,确保包含lastBuild的timestamp字段
|
// 只查询必要的字段,确保包含lastBuild的timestamp字段
|
||||||
String treeQuery = "jobs[name,url,description,buildable,nextBuildNumber," +
|
String treeQuery = "jobs[name,url,description,buildable,nextBuildNumber," +
|
||||||
"lastBuild[number,timestamp,result],color]";
|
"lastBuild[number,timestamp,result],color]";
|
||||||
@ -629,6 +632,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JenkinsJobResponse job(ExternalSystem externalSystem, String jobName) {
|
public JenkinsJobResponse job(ExternalSystem externalSystem, String jobName) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
try {
|
try {
|
||||||
// 1. 构建请求URL
|
// 1. 构建请求URL
|
||||||
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
||||||
@ -677,6 +681,7 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
|
|||||||
* @return 构建信息列表
|
* @return 构建信息列表
|
||||||
*/
|
*/
|
||||||
public List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName) {
|
public List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName) {
|
||||||
|
externalSystem = decryptSystem(externalSystem);
|
||||||
// Jenkins API 默认只返回最近的若干个构建,通过 {from,to} 可以指定范围
|
// Jenkins API 默认只返回最近的若干个构建,通过 {from,to} 可以指定范围
|
||||||
String treeQuery = "builds[number,url,result,timestamp,duration,building,actions[_class,parameters[_class,name,value]]]";
|
String treeQuery = "builds[number,url,result,timestamp,duration,building,actions[_class,parameters[_class,name,value]]]";
|
||||||
List<JenkinsBuildResponse> builds = callJenkinsApi(
|
List<JenkinsBuildResponse> builds = callJenkinsApi(
|
||||||
|
|||||||
@ -197,6 +197,22 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.springframework.data.domain.Page<ExternalSystemDTO> page(ExternalSystemQuery query) {
|
||||||
|
org.springframework.data.domain.Page<ExternalSystemDTO> page = super.page(query);
|
||||||
|
// 查询后处理:用掩码替换敏感数据
|
||||||
|
page.getContent().forEach(this::maskSensitiveData);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ExternalSystemDTO> findAll(ExternalSystemQuery query) {
|
||||||
|
List<ExternalSystemDTO> dtos = super.findAll(query);
|
||||||
|
// 查询后处理:用掩码替换敏感数据
|
||||||
|
dtos.forEach(this::maskSensitiveData);
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public boolean testConnection(Long id) {
|
public boolean testConnection(Long id) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user