diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/common/RSATool.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/common/RSATool.java new file mode 100644 index 00000000..24196ef8 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/common/RSATool.java @@ -0,0 +1,427 @@ +package com.gitee.sop.adminbackend.common; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; + +import javax.crypto.Cipher; +import javax.swing.plaf.PanelUI; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Objects; + +/** + * RSA加解密工具
+ * + * @author 六如 + */ +public class RSATool { + public static String RSA_ALGORITHM = "RSA"; + + private KeyFormat keyFormat; + private KeyLength keyLength; + + public RSATool(KeyFormat keyFormat, KeyLength keyLength) { + this.keyFormat = keyFormat; + this.keyLength = keyLength; + } + + /** + * 创建公钥私钥 + * + * @return 返回公私钥对 + * @throws Exception + */ + public KeyStore createKeys() throws Exception { + KeyPairGenerator keyPairGeno = KeyPairGenerator.getInstance(RSA_ALGORITHM); + keyPairGeno.initialize(keyLength.getLength()); + KeyPair keyPair = keyPairGeno.generateKeyPair(); + + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + + KeyStore keyStore = new KeyStore(); + if (this.keyFormat == KeyFormat.PKCS1) { + keyStore.setPublicKey(Base64.encodeBase64String(publicKey.getEncoded())); + keyStore.setPrivateKey(convertPkcs8ToPkcs1(privateKey.getEncoded())); + } else { + keyStore.setPublicKey(Base64.encodeBase64String(publicKey.getEncoded())); + keyStore.setPrivateKey(Base64.encodeBase64String(privateKey.getEncoded())); + } + return keyStore; + } + + /** + * 获取公钥对象 + * + * @param pubKeyData 公钥 + * @return 返回公钥对象 + * @throws Exception + */ + public RSAPublicKey getPublicKey(byte[] pubKeyData) throws Exception { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyData); + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + return (RSAPublicKey) keyFactory.generatePublic(keySpec); + } + + /** + * 获取公钥对象 + * + * @param pubKey 公钥 + * @return 返回私钥对象 + * @throws Exception + */ + public RSAPublicKey getPublicKey(String pubKey) throws Exception { + return getPublicKey(Base64.decodeBase64(pubKey)); + + } + + /** + * 获取私钥对象 + * + * @param priKey 私钥 + * @return 私钥对象 + * @throws Exception + */ + public RSAPrivateKey getPrivateKey(String priKey) throws Exception { + return getPrivateKey(Base64.decodeBase64(priKey)); + } + + /** + * 通过私钥byte[]将公钥还原,适用于RSA算法 + * + * @param keyBytes + * @return 返回私钥 + * @throws Exception + */ + public RSAPrivateKey getPrivateKey(byte[] keyBytes) throws Exception { + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + return (RSAPrivateKey) keyFactory.generatePrivate(keySpec); + + } + + /** + * 公钥加密 + * + * @param data 待加密内容 + * @param publicKey 公钥 + * @return 返回密文 + * @throws Exception + */ + public String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception { + Cipher cipher = Cipher.getInstance(keyFormat.getCipherAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + // 模长 + int key_len = publicKey.getModulus().bitLength() / 8; + // 加密数据长度 <= 模长-11 + String[] datas = splitString(data, key_len - 11); + String mi = ""; + // 如果明文长度大于模长-11则要分组加密 + for (String s : datas) { + mi += bcd2Str(cipher.doFinal(s.getBytes())); + } + return mi; + } + + public String encryptByPrivateKey(String data, String privateKey) throws Exception { + return encryptByPrivateKey(data, getPrivateKey(privateKey)); + } + + /** + * 私钥加密 + * + * @param data 待加密数据 + * @param privateKey 私钥 + * @return 返回密文 + * @throws Exception + */ + public String encryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception { + Cipher cipher = Cipher.getInstance(keyFormat.getCipherAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + // 模长 + int key_len = privateKey.getModulus().bitLength() / 8; + // 加密数据长度 <= 模长-11 + String[] datas = splitString(data, key_len - 11); + String mi = ""; + // 如果明文长度大于模长-11则要分组加密 + for (String s : datas) { + mi += bcd2Str(cipher.doFinal(s.getBytes())); + } + return mi; + } + + public String decryptByPrivateKey(String data, String privateKey) throws Exception { + return decryptByPrivateKey(data, getPrivateKey(privateKey)); + } + + /** + * 私钥解密 + * + * @param data 待解密内容 + * @param privateKey 私钥 + * @return 返回明文 + * @throws Exception + */ + public String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception { + Cipher cipher = Cipher.getInstance(keyFormat.getCipherAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + // 模长 + int key_len = privateKey.getModulus().bitLength() / 8; + byte[] bytes = data.getBytes(); + byte[] bcd = ASCII_To_BCD(bytes, bytes.length); + // 如果密文长度大于模长则要分组解密 + String ming = ""; + byte[][] arrays = splitArray(bcd, key_len); + for (byte[] arr : arrays) { + ming += new String(cipher.doFinal(arr)); + } + return ming; + } + + /** + * 公钥解密 + * + * @param data 待解密内容 + * @param rsaPublicKey 公钥 + * @return 返回明文 + * @throws Exception + */ + public String decryptByPublicKey(String data, RSAPublicKey rsaPublicKey) throws Exception { + Cipher cipher = Cipher.getInstance(keyFormat.getCipherAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey); + // 模长 + int key_len = rsaPublicKey.getModulus().bitLength() / 8; + byte[] bytes = data.getBytes(); + byte[] bcd = ASCII_To_BCD(bytes, bytes.length); + // 如果密文长度大于模长则要分组解密 + String ming = ""; + byte[][] arrays = splitArray(bcd, key_len); + for (byte[] arr : arrays) { + ming += new String(cipher.doFinal(arr)); + } + return ming; + } + + public static String convertPkcs8ToPkcs1(byte[] privateKeyData) throws Exception{ + PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKeyData); + ASN1Encodable encodable = pkInfo.parsePrivateKey(); + ASN1Primitive primitive = encodable.toASN1Primitive(); + byte[] privateKeyPKCS1 = primitive.getEncoded(); + return Base64.encodeBase64String(privateKeyPKCS1); + } + + + /** + * ASCII码转BCD码 + */ + public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) { + byte[] bcd = new byte[asc_len / 2]; + int j = 0; + for (int i = 0; i < (asc_len + 1) / 2; i++) { + bcd[i] = asc_to_bcd(ascii[j++]); + bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++]) & 0xff) + (bcd[i] << 4)); + } + return bcd; + } + + public static byte asc_to_bcd(byte asc) { + byte bcd; + + if ((asc >= '0') && (asc <= '9')) { + bcd = (byte) (asc - '0'); + } else if ((asc >= 'A') && (asc <= 'F')) { + bcd = (byte) (asc - 'A' + 10); + } else if ((asc >= 'a') && (asc <= 'f')) { + bcd = (byte) (asc - 'a' + 10); + } else { + bcd = (byte) (asc - 48); + } + return bcd; + } + + /** + * BCD转字符串 + */ + public String bcd2Str(byte[] bytes) { + char[] temp = new char[bytes.length * 2]; + char val; + + for (int i = 0; i < bytes.length; i++) { + val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f); + temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0'); + + val = (char) (bytes[i] & 0x0f); + temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0'); + } + return new String(temp); + } + + /** + * 拆分字符串 + */ + public String[] splitString(String string, int len) { + int x = string.length() / len; + int y = string.length() % len; + int z = 0; + if (y != 0) { + z = 1; + } + String[] strings = new String[x + z]; + String str = ""; + for (int i = 0; i < x + z; i++) { + if (i == x + z - 1 && y != 0) { + str = string.substring(i * len, i * len + y); + } else { + str = string.substring(i * len, i * len + len); + } + strings[i] = str; + } + return strings; + } + + /** + * 拆分数组 + */ + public byte[][] splitArray(byte[] data, int len) { + int x = data.length / len; + int y = data.length % len; + int z = 0; + if (y != 0) { + z = 1; + } + byte[][] arrays = new byte[x + z][]; + byte[] arr; + for (int i = 0; i < x + z; i++) { + arr = new byte[len]; + if (i == x + z - 1 && y != 0) { + System.arraycopy(data, i * len, arr, 0, y); + } else { + System.arraycopy(data, i * len, arr, 0, len); + } + arrays[i] = arr; + } + return arrays; + } + + public enum KeyLength { + /** + * 秘钥长度:1024 + */ + LENGTH_1024(1024), + /** + * 秘钥长度:2048 + */ + LENGTH_2048(2048); + private int length; + + KeyLength(int length) { + this.length = length; + } + + public int getLength() { + return length; + } + } + + public static class KeyStore { + private String publicKey; + private String privateKey; + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + } + + @AllArgsConstructor + @Getter + public enum KeyFormat { + PKCS8(1, "RSA"), + PKCS1(2, "RSA/ECB/PKCS1Padding"); + + private Integer value; + private String cipherAlgorithm; + + public static KeyFormat of(Integer value) { + for (KeyFormat keyFormat : KeyFormat.values()) { + if (Objects.equals(value, keyFormat.value)) { + return keyFormat; + } + } + return PKCS8; + } + } + + public KeyFormat getKeyFormat() { + return keyFormat; + } + + public KeyLength getKeyLength() { + return keyLength; + } + + + + /* ------------ Test ------------ + public static void main(String[] args) throws Exception { + + RSATool rsa_pkcs8_1024 = new RSATool(KeyFormat.PKCS8, KeyLength.LENGTH_1024); + RSATool rsa_pkcs8_2048 = new RSATool(KeyFormat.PKCS8, KeyLength.LENGTH_2048); + + doTest(rsa_pkcs8_1024); + doTest(rsa_pkcs8_2048); + + // PKCS在Java环境无法测试,可以生成一对,到非java平台测试,如C# + } + + private static void doTest(RSATool rsaTool) throws Exception { + System.out.println("秘钥格式:" + rsaTool.keyFormat.name() + ", 秘钥长度:" + rsaTool.keyLength.getLength()); + KeyStore keys = rsaTool.createKeys(); + String pubKey = keys.getPublicKey(); + System.out.println("pubKey:"); + System.out.println(pubKey); + String priKey = keys.getPrivateKey(); + System.out.println("priKey:"); + System.out.println(priKey); + System.out.println("--------"); + + String ming = "你好,abc123~!@="; + // 用公钥加密 + String mi = rsaTool.encryptByPublicKey(ming, rsaTool.getPublicKey(pubKey)); + System.out.println("mi : " + mi); + // 用私钥解密 + String ming2 = rsaTool.decryptByPrivateKey(mi, rsaTool.getPrivateKey(priKey)); + System.out.println("ming : " + ming2 + ", 结果:" + ming2.equals(ming)); + + // 用私钥加密 + String mi2 = rsaTool.encryptByPrivateKey(ming, rsaTool.getPrivateKey(priKey)); + + System.out.println("mi2 : " + mi2); + // 用公钥解密 + String ming3 = rsaTool.decryptByPublicKey(mi2, rsaTool.getPublicKey(pubKey)); + System.out.println("ming3 : " + ming3 + ", 结果:" + ming3.equals(ming)); + System.out.println("---------------------"); + } + */ + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/IsvInfoController.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/IsvInfoController.java index 6143fe97..8114eb7b 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/IsvInfoController.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/IsvInfoController.java @@ -3,12 +3,17 @@ package com.gitee.sop.adminbackend.controller.isv; import com.gitee.fastmybatis.core.PageInfo; import com.gitee.fastmybatis.core.query.Query; import com.gitee.fastmybatis.core.query.param.PageParam; -import com.gitee.sop.adminbackend.common.req.IdParam; +import com.gitee.sop.adminbackend.common.RSATool; +import com.gitee.sop.adminbackend.common.dto.StatusUpdateDTO; +import com.gitee.sop.adminbackend.common.req.StatusUpdateParam; import com.gitee.sop.adminbackend.common.resp.Result; -import com.gitee.sop.adminbackend.controller.isv.dto.IsvKeysDTO; +import com.gitee.sop.adminbackend.controller.isv.req.IsvInfoAddParam; +import com.gitee.sop.adminbackend.controller.isv.req.IsvKeysGenParam; import com.gitee.sop.adminbackend.dao.entity.IsvInfo; import com.gitee.sop.adminbackend.service.isv.IsvInfoService; -import org.springframework.beans.factory.annotation.Autowired; +import com.gitee.sop.adminbackend.service.isv.dto.IsvInfoAddDTO; +import com.gitee.sop.adminbackend.service.isv.dto.IsvKeysDTO; +import com.gitee.sop.adminbackend.util.CopyUtil; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -16,6 +21,8 @@ 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; + /** * @author 六如 @@ -24,9 +31,11 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("isv") public class IsvInfoController { - @Autowired + @Resource private IsvInfoService isvInfoService; + + /** * 分页查询 * @@ -40,29 +49,44 @@ public class IsvInfoController { return Result.ok(pageInfo); } + /** + * 生成秘钥 + * + * @param param + * @return + * @throws Exception + */ + @PostMapping("createKeys") + public Result createKeys(IsvKeysGenParam param) throws Exception { + RSATool.KeyFormat format = RSATool.KeyFormat.of(param.getKeyFormat()); + RSATool.KeyStore keyStore = isvInfoService.createKeys(format); + return Result.ok(keyStore); + } + /** * 获取秘钥信息 * - * @param appId + * @param isvInfoId * @return */ @GetMapping("/getKeys") - public Result getKeys(String appId) { - IsvKeysDTO isvKeysDTO = isvInfoService.getKeys(appId); + public Result getKeys(Long isvInfoId) { + IsvKeysDTO isvKeysDTO = isvInfoService.getKeys(isvInfoId); return Result.ok(isvKeysDTO); } /** * 新增记录 * - * @param user + * @param param * @return 返回添加后的主键值 */ @PostMapping("/add") - public Result add(@Validated @RequestBody IsvInfo user) { - isvInfoService.save(user); + public Result add(@Validated @RequestBody IsvInfoAddParam param) throws Exception { + IsvInfoAddDTO isvInfoAddDTO = CopyUtil.copyBean(param, IsvInfoAddDTO::new); + long id = isvInfoService.add(isvInfoAddDTO); // 返回添加后的主键值 - return Result.ok(user.getId()); + return Result.ok(id); } /** @@ -77,15 +101,15 @@ public class IsvInfoController { } /** - * 删除记录 + * 修改状态 * - * @param param 参数 + * @param param 表单数据 * @return 返回影响行数 */ - @PostMapping("/delete") - public Result delete(@Validated @RequestBody IdParam param) { - return Result.ok(isvInfoService.deleteById(param.getId())); + @PostMapping("/updateStatus") + public Result updateStatus(@Validated @RequestBody StatusUpdateParam param) { + StatusUpdateDTO statusUpdateDTO = CopyUtil.copyBean(param, StatusUpdateDTO::new); + return Result.ok(isvInfoService.updateStatus(statusUpdateDTO)); } - } diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoAddParam.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoAddParam.java new file mode 100644 index 00000000..0349afbb --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoAddParam.java @@ -0,0 +1,27 @@ +package com.gitee.sop.adminbackend.controller.isv.req; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; + + +/** + * @author 六如 + */ +@Data +public class IsvInfoAddParam { + + /** + * 1启用,2禁用 + */ + @NotNull + private Integer status; + + /** + * 备注 + */ + @Length(max = 500) + private String remark; + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoUpdateParam.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoUpdateParam.java new file mode 100644 index 00000000..1fabee8b --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvInfoUpdateParam.java @@ -0,0 +1,19 @@ +package com.gitee.sop.adminbackend.controller.isv.req; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + + +/** + * @author 六如 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class IsvInfoUpdateParam extends IsvInfoAddParam { + + @NotNull + private Long id; + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvKeysGenParam.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvKeysGenParam.java new file mode 100644 index 00000000..f7bfa25a --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/req/IsvKeysGenParam.java @@ -0,0 +1,19 @@ +package com.gitee.sop.adminbackend.controller.isv.req; + +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +/** + * @author 六如 + */ +@Data +public class IsvKeysGenParam { + /** + * 秘钥格式,1:PKCS8(JAVA适用),2:PKCS1(非JAVA适用) + */ + @Min(value = 1, message = "秘钥格式错误") + @Max(value = 2, message = "秘钥格式错误") + private Integer keyFormat; +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/serve/ApiInfoController.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/serve/ApiInfoController.java index 58866196..b5b959ad 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/serve/ApiInfoController.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/serve/ApiInfoController.java @@ -81,15 +81,4 @@ public class ApiInfoController { return Result.ok(apiInfoService.updateStatus(statusUpdateDTO)); } - /** - * 删除记录 - * - * @param param 主键id - * @return 返回影响行数 - */ - @PostMapping("/delete") - public Result delete(@Validated @RequestBody IdParam param) { - return Result.ok(apiInfoService.deleteById(param.getId())); - } - } diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/sys/SysAdminUserController.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/sys/SysAdminUserController.java index 99a0a831..dc238ad4 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/sys/SysAdminUserController.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/sys/SysAdminUserController.java @@ -63,15 +63,5 @@ public class SysAdminUserController { return Result.ok(sysAdminUserService.update(sysAdminUser)); } - /** - * 删除记录 - * - * @param param 参数 - * @return 返回影响行数 - */ - @PostMapping("/delete") - public Result delete(@Validated @RequestBody IdParam param) { - return Result.ok(sysAdminUserService.deleteById(param.getId())); - } } diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/IsvKeys.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/IsvKeys.java index 5ba26f77..0a1626ff 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/IsvKeys.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/IsvKeys.java @@ -20,7 +20,10 @@ public class IsvKeys { private Long id; - private String appId; + /** + * isv_info.id + */ + private Long isvInfoId; /** * 秘钥格式,1:PKCS8(JAVA适用),2:PKCS1(非JAVA适用) diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermIsvRole.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermIsvRole.java new file mode 100644 index 00000000..dbdae9d5 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermIsvRole.java @@ -0,0 +1,39 @@ +package com.gitee.sop.adminbackend.dao.entity; + +import java.time.LocalDateTime; + +import com.gitee.fastmybatis.annotation.Pk; +import com.gitee.fastmybatis.annotation.PkStrategy; +import com.gitee.fastmybatis.annotation.Table; + +import lombok.Data; + + +/** + * 表名:perm_isv_role + * 备注:isv角色 + * + * @author 六如 + */ +@Table(name = "perm_isv_role", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT)) +@Data +public class PermIsvRole { + + private Long id; + + /** + * isv_info表id + */ + private Long isvInfoId; + + /** + * 角色code + */ + private String roleCode; + + private LocalDateTime addTime; + + private LocalDateTime updateTime; + + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRole.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRole.java new file mode 100644 index 00000000..bb830f5d --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRole.java @@ -0,0 +1,39 @@ +package com.gitee.sop.adminbackend.dao.entity; + +import java.time.LocalDateTime; + +import com.gitee.fastmybatis.annotation.Pk; +import com.gitee.fastmybatis.annotation.PkStrategy; +import com.gitee.fastmybatis.annotation.Table; + +import lombok.Data; + + +/** + * 表名:perm_role + * 备注:角色表 + * + * @author 六如 + */ +@Table(name = "perm_role", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT)) +@Data +public class PermRole { + + private Long id; + + /** + * 角色代码 + */ + private String roleCode; + + /** + * 角色描述 + */ + private String description; + + private LocalDateTime addTime; + + private LocalDateTime updateTime; + + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRolePermission.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRolePermission.java new file mode 100644 index 00000000..09ee1750 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/entity/PermRolePermission.java @@ -0,0 +1,39 @@ +package com.gitee.sop.adminbackend.dao.entity; + +import java.time.LocalDateTime; + +import com.gitee.fastmybatis.annotation.Pk; +import com.gitee.fastmybatis.annotation.PkStrategy; +import com.gitee.fastmybatis.annotation.Table; + +import lombok.Data; + + +/** + * 表名:perm_role_permission + * 备注:角色权限表 + * + * @author 六如 + */ +@Table(name = "perm_role_permission", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT)) +@Data +public class PermRolePermission { + + private Long id; + + /** + * 角色表code + */ + private String roleCode; + + /** + * api_id + */ + private String routeId; + + private LocalDateTime addTime; + + private LocalDateTime updateTime; + + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermIsvRoleMapper.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermIsvRoleMapper.java new file mode 100644 index 00000000..297f4f6d --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermIsvRoleMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.adminbackend.dao.mapper; + +import com.gitee.fastmybatis.core.mapper.BaseMapper; +import com.gitee.sop.adminbackend.dao.entity.PermIsvRole; + +/** + * @author 六如 + */ +public interface PermIsvRoleMapper extends BaseMapper { + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRoleMapper.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRoleMapper.java new file mode 100644 index 00000000..2b714845 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRoleMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.adminbackend.dao.mapper; + +import com.gitee.fastmybatis.core.mapper.BaseMapper; +import com.gitee.sop.adminbackend.dao.entity.PermRole; + +/** + * @author 六如 + */ +public interface PermRoleMapper extends BaseMapper { + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRolePermissionMapper.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRolePermissionMapper.java new file mode 100644 index 00000000..cb85fbf3 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/dao/mapper/PermRolePermissionMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.adminbackend.dao.mapper; + +import com.gitee.fastmybatis.core.mapper.BaseMapper; +import com.gitee.sop.adminbackend.dao.entity.PermRolePermission; + +/** + * @author 六如 + */ +public interface PermRolePermissionMapper extends BaseMapper { + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/IsvInfoService.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/IsvInfoService.java index d3538464..6063fa4b 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/IsvInfoService.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/IsvInfoService.java @@ -1,15 +1,31 @@ package com.gitee.sop.adminbackend.service.isv; import com.gitee.fastmybatis.core.support.LambdaService; -import com.gitee.sop.adminbackend.controller.isv.dto.IsvKeysDTO; +import com.gitee.fastmybatis.core.util.DateUtil; +import com.gitee.sop.adminbackend.common.RSATool; +import com.gitee.sop.adminbackend.common.dto.StatusUpdateDTO; +import com.gitee.sop.adminbackend.common.enums.StatusEnum; +import com.gitee.sop.adminbackend.common.exception.BizException; import com.gitee.sop.adminbackend.dao.entity.IsvInfo; import com.gitee.sop.adminbackend.dao.entity.IsvKeys; +import com.gitee.sop.adminbackend.dao.entity.PermIsvRole; import com.gitee.sop.adminbackend.dao.mapper.IsvInfoMapper; import com.gitee.sop.adminbackend.dao.mapper.IsvKeysMapper; +import com.gitee.sop.adminbackend.dao.mapper.PermIsvRoleMapper; +import com.gitee.sop.adminbackend.service.isv.dto.IsvInfoAddDTO; +import com.gitee.sop.adminbackend.service.isv.dto.IsvKeysDTO; +import com.gitee.sop.adminbackend.service.isv.dto.IsvKeysGenDTO; import com.gitee.sop.adminbackend.util.CopyUtil; +import com.gitee.sop.adminbackend.util.IdGen; +import org.apache.dubbo.common.utils.CollectionUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; /** @@ -20,10 +36,90 @@ public class IsvInfoService implements LambdaService { @Resource private IsvKeysMapper isvKeysMapper; + @Resource + private PermIsvRoleMapper permIsvRoleMapper; - public IsvKeysDTO getKeys(String appId) { - IsvKeys isvKeys = isvKeysMapper.get(IsvKeys::getAppId, appId); + public RSATool.KeyStore createKeys(RSATool.KeyFormat keyFormat) throws Exception { + if (keyFormat == null) { + keyFormat = RSATool.KeyFormat.PKCS8; + } + RSATool rsaTool = new RSATool(keyFormat, RSATool.KeyLength.LENGTH_2048); + return rsaTool.createKeys(); + } + + + @Transactional(rollbackFor = Exception.class) + public long add(IsvInfoAddDTO isvInfoAddDTO) throws Exception { + IsvInfo rec = CopyUtil.copyBean(isvInfoAddDTO, IsvInfo::new); + String appKey = new SimpleDateFormat("yyyyMMdd").format(new Date()) + IdGen.nextId(); + rec.setAppId(appKey); + rec.setStatus(StatusEnum.ENABLE.getStatus()); + this.save(rec); + if (CollectionUtils.isNotEmpty(isvInfoAddDTO.getRoleCodes())) { + this.saveIsvRole(rec, isvInfoAddDTO.getRoleCodes()); + } + IsvKeysGenDTO isvKeysGenVO = this.createIsvKeys(); + IsvKeys isvKeys = new IsvKeys(); + isvKeys.setIsvInfoId(rec.getId()); + CopyUtil.copyPropertiesIgnoreNull(isvKeysGenVO, isvKeys); + isvKeysMapper.saveIgnoreNull(isvKeys); + return rec.getId(); + } + + private void saveIsvRole(IsvInfo isvInfo, List roleCodeList) { + long isvInfoId = isvInfo.getId(); + permIsvRoleMapper.deleteByColumn(PermIsvRole::getIsvInfoId, isvInfoId); + + + List tobeSaveList = roleCodeList.stream() + .map(roleCode -> { + PermIsvRole rec = new PermIsvRole(); + rec.setIsvInfoId(isvInfoId); + rec.setRoleCode(roleCode); + return rec; + }) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(tobeSaveList)) { + permIsvRoleMapper.saveBatchIgnoreNull(tobeSaveList); + } + +// try { +// routePermissionService.sendIsvRolePermissionMsg(isvInfo.getAppKey(), roleCodeList); +// } catch (Exception e) { +// log.error("同步角色失败,isvInfo:{}, roleCodeList:{}", isvInfo, roleCodeList); +// throw new BizException("同步角色失败,请查看网关日志"); +// } + } + + private IsvKeysGenDTO createIsvKeys() throws Exception { + IsvKeysGenDTO isvKeysGenDTO = new IsvKeysGenDTO(); + + RSATool.KeyStore keyStoreIsv = this.createKeys(RSATool.KeyFormat.PKCS8); + isvKeysGenDTO.setPublicKeyIsv(keyStoreIsv.getPublicKey()); + isvKeysGenDTO.setPrivateKeyIsv(keyStoreIsv.getPrivateKey()); + + isvKeysGenDTO.setPublicKeyPlatform(""); + isvKeysGenDTO.setPrivateKeyPlatform(""); + return isvKeysGenDTO; + } + + public IsvKeysDTO getKeys(Long isvInfoId) { + IsvKeys isvKeys = isvKeysMapper.get(IsvKeys::getIsvInfoId, isvInfoId); return CopyUtil.copyBean(isvKeys, IsvKeysDTO::new); } + /** + * 修改状态 + * + * @param statusUpdateDTO 修改值 + * @return 返回影响行数 + */ + public int updateStatus(StatusUpdateDTO statusUpdateDTO) { + return this.query() + .eq(IsvInfo::getId, statusUpdateDTO.getId()) + .set(IsvInfo::getStatus, statusUpdateDTO.getStatus()) + .update(); + } + } diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvInfoAddDTO.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvInfoAddDTO.java new file mode 100644 index 00000000..1af3c347 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvInfoAddDTO.java @@ -0,0 +1,33 @@ +package com.gitee.sop.adminbackend.service.isv.dto; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; +import java.util.List; + + +/** + * @author 六如 + */ +@Data +public class IsvInfoAddDTO { + + /** + * 1启用,2禁用 + */ + @NotNull + private Integer status; + + /** + * 备注 + */ + @Length(max = 500) + private String remark; + + /** + * 角色code + */ + private List roleCodes; + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/dto/IsvKeysDTO.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysDTO.java similarity index 91% rename from sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/dto/IsvKeysDTO.java rename to sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysDTO.java index 5777a427..23995d58 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/controller/isv/dto/IsvKeysDTO.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysDTO.java @@ -1,4 +1,4 @@ -package com.gitee.sop.adminbackend.controller.isv.dto; +package com.gitee.sop.adminbackend.service.isv.dto; import lombok.Data; diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysGenDTO.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysGenDTO.java new file mode 100644 index 00000000..5a3470b0 --- /dev/null +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/isv/dto/IsvKeysGenDTO.java @@ -0,0 +1,31 @@ +package com.gitee.sop.adminbackend.service.isv.dto; + +import lombok.Data; + +/** + * @author 六如 + */ +@Data +public class IsvKeysGenDTO { + + /** + * 开发者生成的公钥, 数据库字段:public_key_isv + */ + private String publicKeyIsv; + + /** + * 开发者生成的私钥(交给开发者), 数据库字段:private_key_isv + */ + private String privateKeyIsv; + + /** + * 平台生成的公钥(交给开发者), 数据库字段:public_key_platform + */ + private String publicKeyPlatform; + + /** + * 平台生成的私钥, 数据库字段:private_key_platform + */ + private String privateKeyPlatform; + +} diff --git a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/serve/ApiInfoService.java b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/serve/ApiInfoService.java index 2f6529bf..3f3fa733 100644 --- a/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/serve/ApiInfoService.java +++ b/sop-admin/sop-admin-backend/src/main/java/com/gitee/sop/adminbackend/service/serve/ApiInfoService.java @@ -13,6 +13,12 @@ import org.springframework.stereotype.Service; @Service public class ApiInfoService implements LambdaService { + /** + * 修改状态 + * + * @param statusUpdateDTO 修改值 + * @return 返回影响行数 + */ public int updateStatus(StatusUpdateDTO statusUpdateDTO) { return this.query() .eq(ApiInfo::getId, statusUpdateDTO.getId()) diff --git a/sop-admin/sop-admin-frontend/src/api/isvList.ts b/sop-admin/sop-admin-frontend/src/api/isvList.ts index 7c4f0d52..eb166553 100644 --- a/sop-admin/sop-admin-frontend/src/api/isvList.ts +++ b/sop-admin/sop-admin-frontend/src/api/isvList.ts @@ -7,7 +7,8 @@ const apiUrl: any = createUrl({ add: "/isv/add", update: "/isv/update", del: "/isv/delete", - getKeys: "/isv/getKeys" + getKeys: "/isv/getKeys", + updateStatus: "/isv/updateStatus" }); /** @@ -48,5 +49,12 @@ export const api: any = { */ viewKeys(params: object) { return http.get(apiUrl.getKeys, { params }); + }, + /** + * 修改状态 + * @param data 表单内容 + */ + updateStatus(data: object) { + return http.post(apiUrl.updateStatus, { data }); } }; diff --git a/sop-admin/sop-admin-frontend/src/views/isv/list/index.ts b/sop-admin/sop-admin-frontend/src/views/isv/list/index.ts index d82bdd1b..d24e1bbc 100644 --- a/sop-admin/sop-admin-frontend/src/views/isv/list/index.ts +++ b/sop-admin/sop-admin-frontend/src/views/isv/list/index.ts @@ -127,19 +127,27 @@ actionButtons.value = [ } }, { - // 删除 - text: "删除", + // 启用/禁用 + text: row => (row.status === StatusEnum.ENABLE ? "禁用" : "启用"), code: "delete", - props: { - type: "danger" - }, confirm: { + message: data => { + const opt = data.row.status === StatusEnum.ENABLE ? "禁用" : "启用"; + return `确定${opt}吗?`; + }, options: { draggable: false } }, onConfirm(params: ButtonsCallBackParams) { - api.del(params).then(() => { + const data = { + id: params.row.id, + status: + params.row.status === StatusEnum.ENABLE + ? StatusEnum.DISABLE + : StatusEnum.ENABLE + }; + api.updateStatus(data).then(() => { ElMessage({ - message: "删除成功", + message: "修改成功", type: "success" }); dlgShow.value = false; diff --git a/sop-admin/sop-admin-frontend/src/views/isv/list/showKeys.ts b/sop-admin/sop-admin-frontend/src/views/isv/list/showKeys.ts index 60589600..0d79d003 100644 --- a/sop-admin/sop-admin-frontend/src/views/isv/list/showKeys.ts +++ b/sop-admin/sop-admin-frontend/src/views/isv/list/showKeys.ts @@ -77,7 +77,7 @@ export const showKeysFormColumns: PlusFormGroupRow[] = [ export const viewKeys = (row: any) => { const params = { - appId: row.appId + isvInfoId: row.id }; api.viewKeys(params).then(resp => { showKeysFormData.value = resp.data; diff --git a/sop-admin/sop-admin-frontend/src/views/serve/api/index.ts b/sop-admin/sop-admin-frontend/src/views/serve/api/index.ts index 05850d68..26662e80 100644 --- a/sop-admin/sop-admin-frontend/src/views/serve/api/index.ts +++ b/sop-admin/sop-admin-frontend/src/views/serve/api/index.ts @@ -156,7 +156,7 @@ actionButtons.value = [ } }, { - // 删除 + // 启用/禁用 text: row => (row.status === StatusEnum.ENABLE ? "禁用" : "启用"), code: "delete", confirm: {