增加密码加密

This commit is contained in:
dengqichen 2025-11-11 14:44:22 +08:00
parent 3d454a0802
commit 9d42dd1ba3
4 changed files with 112 additions and 11 deletions

View File

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

View File

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

View File

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

View File

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