ca管理
This commit is contained in:
parent
c18cfda28b
commit
a9b35329ce
@ -0,0 +1,15 @@
|
|||||||
|
package com.sunyard.chsm.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.sunyard.chsm.model.entity.CaCert;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/6
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CaCertMapper extends BaseMapper<CaCert> {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.sunyard.chsm.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/11
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("sp_ca_cert")
|
||||||
|
public class CaCert {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String caName;
|
||||||
|
private String caUrl;
|
||||||
|
// SM2, RSA
|
||||||
|
private String keyAlg;
|
||||||
|
private String status;
|
||||||
|
private String subject;
|
||||||
|
private String serialNumber;
|
||||||
|
private String issuerDn;
|
||||||
|
private Date notBefore;
|
||||||
|
private Date notAfter;
|
||||||
|
private String pubKey;
|
||||||
|
|
||||||
|
private String certText;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.sunyard.chsm.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.sunyard.chsm.constant.AuditLogConst;
|
||||||
|
import com.sunyard.chsm.dto.CertDTO;
|
||||||
|
import com.sunyard.chsm.model.R;
|
||||||
|
import com.sunyard.chsm.service.CaCertService;
|
||||||
|
import com.sunyard.ssp.common.annotation.AuditControllerLog;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA管理接口
|
||||||
|
*
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/11
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ca/cert")
|
||||||
|
public class CaController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CaCertService caCertService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询CA列表
|
||||||
|
*
|
||||||
|
* @param query query
|
||||||
|
* @return 列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/pageList")
|
||||||
|
public R<Page<CertDTO.CAView>> queryPageList(CertDTO.CAQuery query) {
|
||||||
|
|
||||||
|
Page<CertDTO.CAView> page = caCertService.selectPageList(query);
|
||||||
|
|
||||||
|
return R.data(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增CA
|
||||||
|
*
|
||||||
|
* @param caInfo 证书
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public R<Long> save(@Valid @RequestBody CertDTO.CaInfo caInfo) {
|
||||||
|
Long id = caCertService.save(caInfo);
|
||||||
|
return R.data(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改CA
|
||||||
|
*
|
||||||
|
* @param update 参数
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
@PutMapping
|
||||||
|
@AuditControllerLog(description = "修改CA", operateType = AuditLogConst.UPDATE)
|
||||||
|
public R<Void> update(@Valid @RequestBody CertDTO.CaInfo update) {
|
||||||
|
caCertService.update(update);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除CA
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
@DeleteMapping
|
||||||
|
@AuditControllerLog(description = "删除CA", operateType = AuditLogConst.DELETE)
|
||||||
|
public R<Void> delete(Long id) {
|
||||||
|
caCertService.delete(id);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package com.sunyard.chsm.controller;
|
package com.sunyard.chsm.controller;
|
||||||
|
|
||||||
|
import com.sunyard.chsm.dto.TmkStatus;
|
||||||
import com.sunyard.chsm.model.R;
|
import com.sunyard.chsm.model.R;
|
||||||
import com.sunyard.chsm.service.DeviceService;
|
import com.sunyard.chsm.service.DeviceService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@ -23,6 +25,12 @@ public class TmkController {
|
|||||||
@Resource
|
@Resource
|
||||||
private DeviceService deviceService;
|
private DeviceService deviceService;
|
||||||
|
|
||||||
|
@GetMapping("/status")
|
||||||
|
public R<TmkStatus> getTMKStatus() {
|
||||||
|
TmkStatus status = deviceService.getTMKStatus();
|
||||||
|
return R.data(status);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化主密钥
|
* 初始化主密钥
|
||||||
*/
|
*/
|
||||||
|
@ -95,8 +95,53 @@ public abstract class CertDTO {
|
|||||||
* 加密密钥信封
|
* 加密密钥信封
|
||||||
*/
|
*/
|
||||||
private String envelopedKey;
|
private String envelopedKey;
|
||||||
|
private String remark;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class CaInfo {
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 密钥算法 目前支持: SM2
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "密钥算法不能为空")
|
||||||
|
private String keyAlg;
|
||||||
|
@NotEmpty(message = "CA名称不能为空")
|
||||||
|
private String caName;
|
||||||
|
private String caUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根证书内容
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "根证书不能为空")
|
||||||
|
private String certText;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public static class CAQuery extends PageQuery {
|
||||||
|
|
||||||
|
private String caName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class CAView {
|
||||||
|
private Long id;
|
||||||
|
private String caName;
|
||||||
|
private String caUrl;
|
||||||
|
/**
|
||||||
|
* 密钥算法
|
||||||
|
*/
|
||||||
|
private String keyAlg;
|
||||||
|
/**
|
||||||
|
* 证书DN
|
||||||
|
*/
|
||||||
|
private String subject;
|
||||||
|
private String remark;
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.sunyard.chsm.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/11
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TmkStatus {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已经存在设备
|
||||||
|
*/
|
||||||
|
private boolean hasDevice;
|
||||||
|
/**
|
||||||
|
* 主密钥是否初始化
|
||||||
|
*/
|
||||||
|
private boolean tmkInit;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.sunyard.chsm.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.sunyard.chsm.dto.CertDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/11
|
||||||
|
*/
|
||||||
|
public interface CaCertService {
|
||||||
|
|
||||||
|
Page<CertDTO.CAView> selectPageList(CertDTO.CAQuery query);
|
||||||
|
|
||||||
|
Long save(CertDTO.CaInfo caInfo);
|
||||||
|
|
||||||
|
void update(CertDTO.CaInfo update);
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.sunyard.chsm.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.sunyard.chsm.dto.DeviceDTO;
|
import com.sunyard.chsm.dto.DeviceDTO;
|
||||||
|
import com.sunyard.chsm.dto.TmkStatus;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ public interface DeviceService {
|
|||||||
|
|
||||||
void delete(Long id);
|
void delete(Long id);
|
||||||
|
|
||||||
void initTmk();
|
TmkStatus getTMKStatus();
|
||||||
|
|
||||||
|
void initTmk();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
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.CertDTO;
|
||||||
|
import com.sunyard.chsm.mapper.CaCertMapper;
|
||||||
|
import com.sunyard.chsm.model.entity.CaCert;
|
||||||
|
import com.sunyard.chsm.service.CaCertService;
|
||||||
|
import com.sunyard.chsm.utils.gm.BCECUtils;
|
||||||
|
import com.sunyard.chsm.utils.gm.cert.BCSM2CertUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||||
|
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.security.PublicKey;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liulu
|
||||||
|
* @since 2024/11/11
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class CaCertServiceImpl implements CaCertService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CaCertMapper caCertMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<CertDTO.CAView> selectPageList(CertDTO.CAQuery query) {
|
||||||
|
IPage<CaCert> page = caCertMapper.selectPage(
|
||||||
|
new Page<>(query.getPageNumber(), query.getPageSize()),
|
||||||
|
new LambdaQueryWrapper<CaCert>()
|
||||||
|
.like(StringUtils.hasText(query.getCaName()), CaCert::getCaName, query.getCaName())
|
||||||
|
.orderByDesc(CaCert::getCreateTime)
|
||||||
|
);
|
||||||
|
List<CaCert> records = page.getRecords();
|
||||||
|
if (CollectionUtils.isEmpty(records)) {
|
||||||
|
return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CertDTO.CAView> viewList = records.stream()
|
||||||
|
.map(it -> {
|
||||||
|
CertDTO.CAView view = new CertDTO.CAView();
|
||||||
|
BeanUtils.copyProperties(it, view);
|
||||||
|
return view;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return new Page<CertDTO.CAView>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(viewList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long save(CertDTO.CaInfo caInfo) {
|
||||||
|
checkName(caInfo.getCaName());
|
||||||
|
|
||||||
|
X509Certificate x509Cert;
|
||||||
|
try {
|
||||||
|
x509Cert = BCSM2CertUtils.getX509Cert(caInfo.getCertText());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IllegalArgumentException("证书内容格式错误,无法解析");
|
||||||
|
}
|
||||||
|
|
||||||
|
CaCert cert = genCaCert(caInfo, x509Cert);
|
||||||
|
cert.setId(IdWorker.getId());
|
||||||
|
cert.setCreateTime(LocalDateTime.now());
|
||||||
|
caCertMapper.insert(cert);
|
||||||
|
|
||||||
|
return cert.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(CertDTO.CaInfo update) {
|
||||||
|
Assert.notNull(update.getId(), "id不能为空");
|
||||||
|
CaCert exist = caCertMapper.selectById(update.getId());
|
||||||
|
Assert.notNull(exist, "id对应的CA不存在");
|
||||||
|
|
||||||
|
if (!Objects.equals(exist.getCaName(), update.getCaName())) {
|
||||||
|
checkName(update.getCaName());
|
||||||
|
}
|
||||||
|
|
||||||
|
X509Certificate x509Cert;
|
||||||
|
try {
|
||||||
|
x509Cert = BCSM2CertUtils.getX509Cert(update.getCertText());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IllegalArgumentException("证书内容格式错误,无法解析");
|
||||||
|
}
|
||||||
|
|
||||||
|
CaCert cert = genCaCert(update, x509Cert);
|
||||||
|
cert.setId(update.getId());
|
||||||
|
cert.setUpdateTime(LocalDateTime.now());
|
||||||
|
caCertMapper.updateById(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static CaCert genCaCert(CertDTO.CaInfo caInfo, X509Certificate x509Cert) {
|
||||||
|
|
||||||
|
CaCert cert = new CaCert();
|
||||||
|
cert.setKeyAlg(caInfo.getKeyAlg());
|
||||||
|
cert.setCaName(caInfo.getCaName());
|
||||||
|
cert.setCaUrl(caInfo.getCaUrl());
|
||||||
|
cert.setCertText(caInfo.getCertText());
|
||||||
|
cert.setRemark(caInfo.getRemark());
|
||||||
|
|
||||||
|
cert.setSubject(x509Cert.getSubjectX500Principal().getName());
|
||||||
|
cert.setSerialNumber(x509Cert.getSerialNumber().toString());
|
||||||
|
cert.setIssuerDn(x509Cert.getIssuerX500Principal().getName());
|
||||||
|
cert.setNotBefore(x509Cert.getNotBefore());
|
||||||
|
cert.setNotAfter(x509Cert.getNotAfter());
|
||||||
|
|
||||||
|
PublicKey publicKey = x509Cert.getPublicKey();
|
||||||
|
String hexPubKey = BCECUtils.getHexPubKey((BCECPublicKey) publicKey);
|
||||||
|
cert.setPubKey(hexPubKey);
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkName(String name) {
|
||||||
|
|
||||||
|
CaCert exist = caCertMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<CaCert>().eq(CaCert::getCaName, name)
|
||||||
|
);
|
||||||
|
Assert.isNull(exist, "CA名称已经存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Long id) {
|
||||||
|
caCertMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.sunyard.chsm.dto.DeviceDTO;
|
import com.sunyard.chsm.dto.DeviceDTO;
|
||||||
|
import com.sunyard.chsm.dto.TmkStatus;
|
||||||
import com.sunyard.chsm.enums.ManufacturerEnum;
|
import com.sunyard.chsm.enums.ManufacturerEnum;
|
||||||
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
||||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
||||||
@ -181,6 +182,21 @@ public class DeviceServiceImpl implements DeviceService {
|
|||||||
spDeviceMapper.deleteById(id);
|
spDeviceMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TmkStatus getTMKStatus() {
|
||||||
|
TmkStatus status = new TmkStatus();
|
||||||
|
ParamConf tmkInit = paramConfMapper.selectByKey("tmk_init");
|
||||||
|
if (tmkInit != null && "true".equals(tmkInit.getValue())) {
|
||||||
|
status.setHasDevice(true);
|
||||||
|
status.setTmkInit(false);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
status.setTmkInit(false);
|
||||||
|
Long c = spDeviceMapper.selectCount(new LambdaQueryWrapper<>());
|
||||||
|
status.setHasDevice(c > 0L);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initTmk() {
|
public void initTmk() {
|
||||||
ParamConf tmkInit = paramConfMapper.selectByKey("tmk_init");
|
ParamConf tmkInit = paramConfMapper.selectByKey("tmk_init");
|
||||||
|
@ -189,7 +189,7 @@ CREATE TABLE sp_key_csr (
|
|||||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
-- 证书
|
-- 应用证书
|
||||||
CREATE TABLE sp_app_cert (
|
CREATE TABLE sp_app_cert (
|
||||||
id BIGINT NOT NULL COMMENT 'id',
|
id BIGINT NOT NULL COMMENT 'id',
|
||||||
application_id BIGINT NOT NULL COMMENT '应用id',
|
application_id BIGINT NOT NULL COMMENT '应用id',
|
||||||
@ -214,3 +214,22 @@ CREATE TABLE sp_app_cert (
|
|||||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
-- CA证书
|
||||||
|
CREATE TABLE sp_ca_cert (
|
||||||
|
id BIGINT NOT NULL COMMENT 'id',
|
||||||
|
ca_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'ca name',
|
||||||
|
ca_url VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'url',
|
||||||
|
key_alg VARCHAR(30) NOT NULL DEFAULT '' COMMENT '密钥算法',
|
||||||
|
status VARCHAR(30) DEFAULT '' COMMENT '状态',
|
||||||
|
subject VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'DN',
|
||||||
|
serial_number VARCHAR(255) NOT NULL DEFAULT '' COMMENT '证书号',
|
||||||
|
issuer_dn VARCHAR(255) NOT NULL DEFAULT '' COMMENT '颁发者',
|
||||||
|
not_before TIMESTAMP NOT NULL COMMENT '开始时间',
|
||||||
|
not_after TIMESTAMP NOT NULL COMMENT '结束时间',
|
||||||
|
pub_key VARCHAR(255) NOT NULL DEFAULT '' COMMENT '公钥',
|
||||||
|
cert_text VARCHAR(4099) NOT NULL DEFAULT '' COMMENT '证书',
|
||||||
|
remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||||
|
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user