应用管理

This commit is contained in:
liulu
2024-11-01 15:51:47 +08:00
parent b5df4c2406
commit c82f7d8013
12 changed files with 296 additions and 42 deletions
@@ -62,6 +62,20 @@ public class ApplicationController {
return R.data(String.valueOf(id));
}
/**
* 修改应用
*
* @param update 参数
* @return 应用
*/
@PutMapping
@AuditControllerLog(description = "修改应用", operateType = AuditLogConst.UPDATE)
public R<Void> update(@Valid @RequestBody AppSave update) {
Assert.notNull(update.getId(), "应用id不能为空");
applicationService.update(update);
return R.ok();
}
/**
* 启用应用
*
@@ -91,18 +105,20 @@ public class ApplicationController {
}
/**
* 修改应用
* 更新访问凭证
*
* @param update 参数
* @return 应用
* @param id 应用id
* @return
*/
@PutMapping
public R<Void> update(@Valid @RequestBody AppSave update) {
Assert.notNull(update.getId(), "应用id不能为空");
applicationService.update(update);
@PostMapping("/reset/credential")
@AuditControllerLog(description = "更新访问凭证", operateType = AuditLogConst.UPDATE)
public R<Void> resetCredential(Long id) {
Assert.notNull(id, "应用id不能为空");
applicationService.resetCredential(id);
return R.ok();
}
/**
* 删除应用
*
@@ -2,6 +2,11 @@ package com.sunyard.chsm.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.List;
/**
* @author liulu
* @since 2024/10/30
@@ -9,7 +14,18 @@ import lombok.Data;
@Data
public class AppSave {
private Long id;
/**
* 应用名称
*/
@NotBlank(message = "应用名称不能为空")
private String name;
/**
* 密码服务ids
*/
@NotEmpty(message = "密码服务不能为空")
private List<Long> serviceIds;
@Size(max = 500, message = "备注长度在1-500之间")
private String remark;
}
@@ -2,6 +2,9 @@ package com.sunyard.chsm.dto;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author liulu
* @since 2024/10/30
@@ -9,8 +12,16 @@ import lombok.Data;
@Data
public class AppView {
private Long id;
private String name;
private List<String> serviceIds;
private String serviceNames;
private String status;
private String statusText;
private String appKey;
private String appSecret;
private String remark;
private LocalDateTime createTime;
}
@@ -28,6 +28,7 @@ public abstract class KeyInfoDTO {
@Data
public static class KeySave {
@NotNull(message = "所属应用不能为空")
private Long applicationId;
/**
* 密钥模版编码
@@ -45,6 +46,8 @@ public abstract class KeyInfoDTO {
@Data
public static class KeyView {
private Long id;
private Long applicationId;
private String appName;
/**
* KEY_ID
*/
@@ -81,7 +84,7 @@ public abstract class KeyInfoDTO {
/**
* 密钥id列表
*/
@Size(min = 1, max = 100,message = "密钥id列表长度在1-100之间")
@Size(min = 1, max = 100, message = "密钥id列表长度在1-100之间")
@NotNull(message = "密钥id列表不能为空")
private List<Long> ids;
@@ -90,7 +93,7 @@ public abstract class KeyInfoDTO {
@EqualsAndHashCode(callSuper = true)
@Data
public static class KeyUpdate extends IDs{
public static class KeyUpdate extends IDs {
/**
* 新密钥生效时间 yyyy-MM-dd
*/
@@ -21,5 +21,7 @@ public interface ApplicationService {
void disable(Long id);
void resetCredential(Long id);
void delete(Long id);
}
@@ -1,15 +1,35 @@
package com.sunyard.chsm.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.dto.AppQuery;
import com.sunyard.chsm.dto.AppSave;
import com.sunyard.chsm.dto.AppView;
import com.sunyard.chsm.enums.EnableStatus;
import com.sunyard.chsm.mapper.AppServiceMapper;
import com.sunyard.chsm.mapper.ApplicationMapper;
import com.sunyard.chsm.mapper.CryptoServiceMapper;
import com.sunyard.chsm.model.entity.AppService;
import com.sunyard.chsm.model.entity.Application;
import com.sunyard.chsm.model.entity.CryptoService;
import com.sunyard.chsm.service.ApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author liulu
@@ -22,34 +42,162 @@ public class ApplicationServiceImpl implements ApplicationService {
@Resource
private ApplicationMapper applicationMapper;
@Resource
private AppServiceMapper appServiceMapper;
@Resource
private CryptoServiceMapper cryptoServiceMapper;
@Override
public Page<AppView> selectPageList(AppQuery query) {
return null;
IPage<Application> page = applicationMapper.selectPage(
new Page<>(query.getPageNumber(), query.getPageSize()),
new LambdaQueryWrapper<Application>()
.like(StringUtils.hasText(query.getName()), Application::getName, query.getName())
.eq(StringUtils.hasText(query.getStatus()), Application::getStatus, query.getStatus())
.orderByDesc(Application::getCreateTime)
);
List<Application> records = page.getRecords();
if (CollectionUtils.isEmpty(records)) {
return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
}
List<Long> appIds = records.stream().map(Application::getId).collect(Collectors.toList());
List<AppService> appServices = appServiceMapper.selectByAppIds(appIds);
Map<Long, List<Long>> appServiceMap = appServices.stream()
.collect(Collectors.groupingBy(AppService::getApplicationId,
Collectors.mapping(AppService::getServiceId, Collectors.toList())));
List<CryptoService> services = cryptoServiceMapper.selectBatchIds(appServices.stream().map(AppService::getServiceId).collect(Collectors.toList()));
Map<Long, String> snMap = services.stream().collect(Collectors.toMap(CryptoService::getId, CryptoService::getName));
List<AppView> viewList = records.stream()
.map(it -> {
AppView view = new AppView();
BeanUtils.copyProperties(it, view);
List<Long> sIds = appServiceMap.getOrDefault(it.getId(), Collections.emptyList());
view.setServiceIds(sIds.stream().map(String::valueOf).collect(Collectors.toList()));
String sn = sIds.stream()
.map(snMap::get)
.filter(Objects::nonNull)
.collect(Collectors.joining(","));
view.setServiceNames(sn);
view.setStatusText(EnableStatus.of(it.getStatus()).getDesc());
return view;
})
.collect(Collectors.toList());
return new Page<AppView>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(viewList);
}
@Override
public Long save(AppSave save) {
return null;
checkName(save.getName());
LocalDateTime now = LocalDateTime.now();
Application app = new Application();
app.setId(IdWorker.getId());
app.setAppKey(IdWorker.get32UUID());
app.setAppSecret(IdWorker.get32UUID());
app.setName(save.getName());
app.setStatus(EnableStatus.ENABLED.getCode());
app.setRemark(save.getRemark());
app.setCreateTime(now);
applicationMapper.insert(app);
for (Long serviceId : save.getServiceIds()) {
AppService as = new AppService();
as.setId(IdWorker.getId());
as.setApplicationId(app.getId());
as.setServiceId(serviceId);
as.setCreateTime(now);
appServiceMapper.insert(as);
}
return app.getId();
}
@Override
public void update(AppSave update) {
Assert.notNull(update.getId(), "id不能为空");
Application exist = applicationMapper.selectById(update.getId());
Assert.notNull(exist, "要更新的数据不存在");
if (!Objects.equals(exist.getName(), update.getName())) {
checkName(update.getName());
}
LocalDateTime now = LocalDateTime.now();
Application upApp = new Application();
upApp.setId(update.getId());
upApp.setName(update.getName());
upApp.setRemark(update.getRemark());
upApp.setUpdateTime(now);
applicationMapper.updateById(upApp);
appServiceMapper.deleteByAppId(update.getId());
for (Long serviceId : update.getServiceIds()) {
AppService as = new AppService();
as.setId(IdWorker.getId());
as.setApplicationId(exist.getId());
as.setServiceId(serviceId);
as.setCreateTime(now);
appServiceMapper.insert(as);
}
}
private void checkName(String name) {
Assert.hasText(name, "名称不能为空");
Application exist = applicationMapper.selectOne(
new LambdaQueryWrapper<Application>()
.eq(Application::getName, name)
);
Assert.notNull(exist, "应用名称已存在");
}
@Override
public void enable(Long id) {
Application app = applicationMapper.selectById(id);
Assert.notNull(app, "业务应用不存在");
Assert.isTrue(Objects.equals(EnableStatus.DISABLED.getCode(), app.getStatus()),
"当前应用不是停用状态,不支持启用");
Application upApp = new Application();
upApp.setId(id);
upApp.setStatus(EnableStatus.ENABLED.getCode());
upApp.setUpdateTime(LocalDateTime.now());
applicationMapper.updateById(upApp);
}
@Override
public void disable(Long id) {
Application app = applicationMapper.selectById(id);
Assert.notNull(app, "业务应用不存在");
Assert.isTrue(Objects.equals(EnableStatus.ENABLED.getCode(), app.getStatus()),
"当前应用不是启用状态,不支持停用");
Application upApp = new Application();
upApp.setId(id);
upApp.setStatus(EnableStatus.DISABLED.getCode());
upApp.setUpdateTime(LocalDateTime.now());
applicationMapper.updateById(upApp);
}
@Override
public void resetCredential(Long id) {
Application app = applicationMapper.selectById(id);
Assert.notNull(app, "业务应用不存在");
Application upApp = new Application();
upApp.setId(id);
upApp.setAppKey(IdWorker.get32UUID());
upApp.setAppSecret(IdWorker.get32UUID());
upApp.setUpdateTime(LocalDateTime.now());
applicationMapper.updateById(upApp);
}
@Override
public void delete(Long id) {
applicationMapper.deleteById(id);
appServiceMapper.deleteByAppId(id);
}
}
@@ -6,13 +6,16 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.dto.KeyInfoDTO;
import com.sunyard.chsm.enums.EnableStatus;
import com.sunyard.chsm.enums.KeyCategory;
import com.sunyard.chsm.enums.KeyStatus;
import com.sunyard.chsm.enums.KeyUsage;
import com.sunyard.chsm.mapper.ApplicationMapper;
import com.sunyard.chsm.mapper.KeyCsrMapper;
import com.sunyard.chsm.mapper.KeyInfoMapper;
import com.sunyard.chsm.mapper.KeyTemplateMapper;
import com.sunyard.chsm.mapper.SpKeyRecordMapper;
import com.sunyard.chsm.model.entity.Application;
import com.sunyard.chsm.model.entity.KeyCsr;
import com.sunyard.chsm.model.entity.KeyInfo;
import com.sunyard.chsm.model.entity.KeyRecord;
@@ -83,6 +86,8 @@ public class KeyInfoServiceImpl implements KeyInfoService {
@Resource
private KeyTemplateMapper keyTemplateMapper;
@Resource
private ApplicationMapper applicationMapper;
@Resource
private SdfApiService sdfApiService;
@@ -120,13 +125,16 @@ public class KeyInfoServiceImpl implements KeyInfoService {
return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
}
List<Long> appIds = records.stream().map(KeyInfo::getId).collect(Collectors.toList());
Map<Long, String> appNameMap = applicationMapper.selectBatchIds(appIds)
.stream().collect(Collectors.toMap(Application::getId, Application::getName));
List<KeyInfoDTO.KeyView> viewList = records.stream()
.map(it -> {
KeyInfoDTO.KeyView view = new KeyInfoDTO.KeyView();
BeanUtils.copyProperties(it, view);
Optional.ofNullable(KeyCategory.of(it.getKeyType()))
.map(KeyCategory::getDesc)
.ifPresent(view::setKeyTypeText);
Optional.ofNullable(it.getApplicationId()).map(appNameMap::get).ifPresent(view::setAppName);
Optional.of(it.getKeyType()).map(KeyCategory::of).map(KeyCategory::getDesc).ifPresent(view::setKeyTypeText);
Map<String, String> usageMap = KeyUsage.getUsage(it.getKeyUsage())
.stream()
.collect(Collectors.toMap(KeyUsage::getCode, KeyUsage::getDesc));
@@ -160,6 +168,9 @@ public class KeyInfoServiceImpl implements KeyInfoService {
.eq(KeyTemplate::getCode, save.getKeyTemplateCode())
);
Assert.notNull(keyTemplate, "密钥模版不存在");
Application app = applicationMapper.selectById(save.getApplicationId());
Assert.notNull(app, "所属应用不存在");
Assert.isTrue(EnableStatus.DISABLED.getCode().equals(app.getStatus()), "应用不是启用状态");
LocalDateTime now = LocalDateTime.now();
@@ -267,14 +278,14 @@ public class KeyInfoServiceImpl implements KeyInfoService {
if (KeyCategory.SYM_KEY.getCode().equals(info.getKeyType())) {
byte[] symKey = sdfApiService.generateRandom(16);
byte[] encSymKey = sdfApiService.encryptByMKNoPadding(symKey);
byte[] encSymKey = sdfApiService.encryptByMK(symKey);
record.setKeyData(Hex.toHexString(encSymKey));
String checkHash = Hex.toHexString(sdfApiService.hash(symKey));
record.setCheckValue(checkHash);
} else {
EccKey eccKey = sdfApiService.genKeyPairEcc();
byte[] d = eccKey.getPriKey().getD();
byte[] encD = sdfApiService.encryptByMKNoPadding(d);
byte[] encD = sdfApiService.encryptByMK(d);
record.setKeyData(Hex.toHexString(encD));
String checkHash = Hex.toHexString(sdfApiService.hash(d));
record.setCheckValue(checkHash);
@@ -381,7 +392,7 @@ public class KeyInfoServiceImpl implements KeyInfoService {
byte[] y = Arrays.copyOfRange(xy, 32, 64);
ECPublicKeyParameters pubKeyParam = BCECUtils.createECPublicKeyParameters(x, y);
byte[] priKeyBytes = sdfApiService.decryptByMKNoPadding(Hex.decode(record.getKeyData()));
byte[] priKeyBytes = sdfApiService.decryptByMK(Hex.decode(record.getKeyData()));
// byte[][] pri18 = LangUtils.splitAverage(priKeyBytes);
ECPrivateKeyParameters priKeyParam = BCECUtils.createECPrivateKeyParameters(priKeyBytes);
ECDomainParameters domainParams = priKeyParam.getParameters();