锦中一网通办平台第三方系统接入手册
第三方系统加密调用API文档
锦集网-锦中集团文档分享与下载平台,提供产品操作手册、产品资料、知识文档、技术集锦等在线学习。
-
+
首页
第三方系统加密调用API文档
## 第三方系统加密调用API文档 ### 一、加密原理 - 1、前端每次提交前动态生成AES的密钥,并用这密钥来加密提交的参数,然后再用事先分配好的RSA公钥来加密AES密钥,并和加密参数一起提交,加密参数字段为data,加密秘钥为dataKey。 【可能遇到的疑问及解答】 **Q:**为什么用AES密钥来加密参数,而不是用RSA公钥来加密参数? **A:**1、虽然用RSA公钥加密参数后,服务器后端也能解密,但服务器端处理完请求后要将处理结果数据返回给前端,则无法加密,因为服务器端私钥加密后,浏览器前端公钥无法解密,公钥最多只能验签。 2、RSA的公钥加密,私钥解密技术,效率比较低(耗时长),一般适用于少量数据加解密。尤其是服务器端用私钥解密时,如果同时在线请求的用户过多,会导致服务器响应效率下降。但AES对称密钥的加解密算法效率高。因此只用RSA公钥对AES的密钥进行加密,由于AES密钥一般不会太长,所以对效率影响可以忽略,并且RSA公钥对AES的密钥进行加密是在浏览器前端进行的,不会影响服务器效率。 - 2、后端接受到数据后,先用事先分配好的RSA私钥来解密dataKey得到AES密钥,再用AES密钥来解密每个请求参数。 - 3、后端调用接口后返回结果数据使用之前解密dataKey得到AES密钥来加密返回数据并返回给前端。 - 4、前端拿到后端返回数据,需要用之前动态生成AES密钥来解密。 - 说明:此方案用到了对称和非对称加密技术结合,利用对称密钥适用于加密数据量大的数据,而非对称加密只能加密少量数据;因为对称密钥的加密解密是同一个,安全性较差,所以利用非对称加密对称密钥,利用对称密钥来加密数据本体,每次动态生成对称密钥,非对称密钥事先前后端分配好,前后端密钥不一致,这样完美实现了传输过程中的安全性。 - 5、本文中的非对称加解密指RSA加解密,对称加解密指AES加解密。 - 6、关于对称加密和非对称加密。 【对称加解密】 对称加密是指加密和解密的过程用的是同一个密钥,相比较于非对称加解密,对称加解密的效率要高(指加解密速度快)。 【非对称加解密】 非对称加密是指加密和解密的过程用的是不同密钥,根据应用场景不同,有不同的加解密、验签算法。本系统中的非对称加解密建议采用RSA。除了RSA之外,还有DSA算法。在以前开发License平台时,发现DSA算法在Java、.Net、浏览器Javascript端等不同开发语言时,存在兼容性问题,所以不建议采用DSA算法。 ### 二、示例 1、本文档结合一个GTE请求和一个POST请求在Java程序下进行接口调用。 #### ①、获取Token:接口/api/blade-auth/oauth/token 实例使用账号密码获取token,获取token并没有加密。如部署在 http://ywtb.dev.jzkg.cn 站点下,向http://ywtb.dev.jzkg.cn/api/blade-auth/oauth/token 发送POST请求 携带请求头 Tenant-Id:000000 Authorization:Basic c2FiZXIzOnNhYmVyM19zZWNyZXQ= 这两个请求头是框架要求携带的,固定就行,Tenant-Id是租户,Authorization是编码后代表哪一个客户端的。  请求体格式:x-www-form-urlencoded username:系统用户名 password:用户密码 grant_type:授予类型,这里写 password scope:授予范围,这里写 all 注意:获取Token时密码需要进行SM2加密,可根据SM2加密工具进行加密测试,如果在代码中调用接口可直接使用响应的第三方库,这里提供平台SM2 publicKey:04338f979d7c63a33c60990ea73c590adcaaeaab48240b0017b9c20e5823f6022fcfe0be30a234868965d23abb41721ce7c849a4be3afdbe3159a6d228bf6291ca 加密模式(密文拼接顺序):C1C2C3 编码方式:Plain普通编码 参考SM2在线加密网站:https://tool.hiofd.com/sm2-encrypt-online   access_token即为token #### ②、GET请求选择的接口是获取待办接口 ##### 获取待办接口:/api/blade-workflow/process/todoList 如部署在 http://ywtb.dev.jzkg.cn 站点下 向 http://ywtb.dev.jzkg.cn/api/blade-workflow/process/todoList 发送GET请求 携带请求头: Blade-Auth:bearer 获取的Token值 Authorization:Basic c2FiZXI6c2FiZXJfc2VjcmV0 Blade-Requested-With:BladeHttpRequest Authorization和Blade-Requested-With是框架要求必须携带的,固定就行,Authorization是编码后代表哪一个客户端的,Blade-Requested-With是框架鉴权严格模式需要携带的。 先来看一下不加密调用:(部署后无法采用明文调用,截屏为本地测试) 携带相应请求头:  携带相应参数:  返回结果(明文):  加密调用: 携带相应请求头:  携带相应加密参数:  返回结果(密文):  加密参数解释:data:kfQKdaoN8pkqvN9+HGvFccVgTFmTXOQSR2yuVPehrVU= data是使用随机生成的一个32位字符串,即为AES密钥加密参数得到的字符串。在这个例子里AES密钥为:DMx3hkKhIReP5GGHoBGx751006331503。加密的参数是一个JSON字符串,{"current":1,"size":100},就是一个分页参数。参考在线AES加密/解密网站:https://config.net.cn/tools/AES.html  可以看到在在线AES加密工具中将{"current":1,"size":100}加密为kfQKdaoN8pkqvN9+HGvFccVgTFmTXOQSR2yuVPehrVU= 与请求时的data是一致的。  需要注意的是,工作模式为CBC,填充模式为PKCS7、向量为密钥的前16位,密钥长度为32位,输出格式为Base64。这些在使用第三方库进行加密的时候都会用到,如java使用Hutool工具类获取AES加密类。 ```java // 首先获取由AES密钥生成的 AES 类,工作模式:CBC,填充模式:PKCS7,向量取密钥的前16位 AES hutoolAes = new AES("CBC", "PKCS7Padding", aesKey.getBytes(), aesKey.substring(0, 16).getBytes()); // 对请求字符串进行加密 获取加密的二进制数组 byte[] hutoolCryptByte = hutoolAes.encrypt(getInfoStr); // 对hutoolCryptByte进行base64编码为字符串 String hutoolData = Base64.getEncoder().encodeToString(hutoolCryptByte); ``` dataKey:BQAPJipm1DPf6UNsrt2cCTvVGTbHmakVlRBXyXQ7qhcZ9C/iQUucEfKun5cnf5d1H8SsX0tidAnw1jsPBm98DD0lucbbNNBX1Z2DtY9TSVf2b9vOuB8HXc+WDkSXXAJ9ehUrlPZewLBBKa0CbESJoAUe/dBo6OXpN72RzYDlOtw= dataKey是使用RSA公钥加密AES密钥得到的值,后台有与之对应的私钥可以进行解密,是非对称加密。由于使用同样是RSA公钥加密同样的内容,得到的结果不一样,所以无法使用在线工具进行展示。 返回密文解释:返回的密文是通过DMx3hkKhIReP5GGHoBGx751006331503进行AES加密的结果,使用这个秘钥进行解密即可,这个就是自己生成的32为秘钥,解密得到明文。  #### ③Java代码示例: 示例代码中,不仅有bladex框架工具类加密/解密,为了跨语言,也有分步加密/解密。AES与RSA加解密都使用的是第三方hutool工具类,不同的平台可以选用不同的第三方库。发送请求我使用的是bladex框架的HttpRequest类返回的是密文(字符串),不同的平台可以选用不同的第三方库发送http请求。 ```java // RSA公钥 用来加密AES密钥的,后台有与之对应的私钥可以进行解密,是非对称加密 String cryptoPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3gr2jE5o96SeitqtDIUDDNK2UR/2m+JrbXorjYTirYfbkU5iMH+C/izzSEOFf5FAEzmnUYcbETmvrs2Jk2NqgGRrevNWPqo8jx8LKuX25qnDDnYBZQhxht9CwJB3sLAWTTZ7jJ9cCqN8JPaJpXWlOi1e3I+wo8LymwP0un/lJWwIDAQAB"; ``` ```java private static void get() { // RSA公钥 用来加密AES密钥的,后台有与之对应的私钥可以进行解密,是非对称加密 String cryptoPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3gr2jE5o96SeitqtDIUDDNK2UR/2m+JrbXorjYTirYfbkU5iMH+C/izzSEOFf5FAEzmnUYcbETmvrs2Jk2NqgGRrevNWPqo8jx8LKuX25qnDDnYBZQhxht9CwJB3sLAWTTZ7jJ9cCqN8JPaJpXWlOi1e3I+wo8LymwP0un/lJWwIDAQAB"; // 随机获取的 32位 AES密钥,注意长度要符合要求,可以自己随机生成 // String aesKey = AESKeyUtils.generateCustomAESKey(); String aesKey = "DMx3hkKhIReP5GGHoBGx751006331503"; System.err.println("AES密钥 = " + aesKey); // 组装请求数据,是JSON转字符串格式,如 String getInfoStr = "{\"current\":1,\"size\":100}"; JSONObject getInfo = new JSONObject(); getInfo.set("current", 1); getInfo.set("size", 100); String getInfoStr = JSONUtil.toJsonStr(getInfo); // 使用上一步随机生成的AES密钥对JSON转字符串格式请求的数据进行加密,即为data数据 String data = AesUtil.encryptToBase64(getInfoStr, aesKey); System.out.println("data数据 = " + data); // 上面是框架工具类加密,为了跨语言,我尝试分步加密,使用 hutool 工具类 // 首先获取由AES密钥生成的 AES 类,工作模式:CBC,填充模式:PKCS7,向量取密钥的前16位 AES hutoolAes = new AES("CBC", "PKCS7Padding", aesKey.getBytes(), aesKey.substring(0, 16).getBytes()); // 对请求字符串进行加密 获取加密的二进制数组 byte[] hutoolCryptByte = hutoolAes.encrypt(getInfoStr); // 对hutoolCryptByte进行base64编码为字符串 String hutoolData = Base64.getEncoder().encodeToString(hutoolCryptByte); System.err.println("hutool编码的data数据 = " + hutoolData); // 还有dataKey,dataKey是使用RSA公钥加密AES密钥的结果,RSA加密同样使用的是hutool工具类 RSA rsa = new RSA(null, cryptoPublicKey); // 公钥加密 byte[] encrypt = rsa.encrypt(aesKey, StandardCharsets.UTF_8, KeyType.PublicKey); // 加密后的byte[]是二进制数据 通常包含不可打印的字符 需要编码为Base64 String dataKey = Base64.getEncoder().encodeToString(encrypt); System.out.println("dataKey数据 = " + dataKey); // 获取token,无论是第三方使用参数获取、还是使用账号密码获取,获取token是一个比较私密的事情。不过获取token并没有加密,与之前获取token是一样的,因此没有撰写详细写加密解密方式 String token = AESKeyUtils.getToken(); System.out.println("token = " + token); // 发送请求 String cryptResult = org.springblade.core.http.HttpRequest.get("http://ywtb.dev.jzkg.cn/api/blade-workflow/process/todoList") .addHeader("Blade-Auth", "bearer " + token) .addHeader("Authorization", "Basic c2FiZXIzOnNhYmVyM19zZWNyZXQ=") .addHeader("Blade-Requested-With", "BladeHttpRequest") .query("data", data) .query("dataKey", dataKey) .execute().asString(); // cryptResult是调接口返回的密文 System.out.println("加密后的返回结果 = " + cryptResult); // 使用刚才生成的AES密钥进行解密,虽然发送请求的时候没有直接携带AES密钥,但是后台通过RSA私钥对dataKey进行解密获得AES密钥,将请求数据解密,查询完成数据之后又通过AES密钥对返回数据进行加密,所以可以直接使用刚才生成的AES密钥进行解密 String result = AesUtil.decryptFormBase64ToString(cryptResult, aesKey); System.out.println("解密后的返回结果 = " + result); // 上面是框架工具类解密,为了跨语言,我尝试分步解密,使用 hutool 工具类 // 使用刚才生成的hutoolAes进行解密,里面已经封装的将返回的加密文本转为Base64后进行解密,hutoolDecrypt已经是解密后的字节数组,可以直接转为字符串 byte[] hutoolDecrypt = hutoolAes.decrypt(cryptResult); String hutoolResult = new String(hutoolDecrypt, StandardCharsets.UTF_8); System.err.println("hutool解密后的返回结果 = " + hutoolResult); // 获得解密后的JSON字符串文本就可以转为JSON对象进行数据的操作了...... System.err.println("获得解密后的JSON字符串文本就可以转为JSON对象进行数据的操作了......"); } ``` 执行结果:  #### ④、POST请求选择的接口是新增通知公告接口 ##### 获取待办接口:/api/blade-desk/notice/submit 如部署在 http://ywtb.dev.jzkg.cn 站点下 向 http://ywtb.dev.jzkg.cn/api/blade-desk/notice/submit 发送POST请求 携带请求头: Blade-Auth:bearer 获取的Token值 Authorization:Basic c2FiZXI6c2FiZXJfc2VjcmV0 Blade-Requested-With:BladeHttpRequest Authorization和Blade-Requested-With是框架要求必须携带的,固定就行,Authorization是编码后代表哪一个客户端的,Blade-Requested-With是框架鉴权严格模式需要携带的。 先来看一下不加密调用:(部署后无法采用明文调用,截屏为本地测试) 携带相应请求头:  携带相应参数:  返回结果(明文):  添加成功:  加密调用: 携带相应请求头:  携带相应加密参数:  返回结果(密文):  添加成功:  说明:可以看到,加密POST请求与加密GET请求原理基本相同,data与dataKey的详细介绍已经在上面解释过了。不同点就是在发送POST请求时将data与dataKey以JSON格式请求接口获取数据。 GET请求:  POST请求:  Java代码示例: ```java private static void post() { // RSA公钥 用来加密AES密钥的,后台有与之对应的私钥可以进行解密,是非对称加密 String cryptoPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3gr2jE5o96SeitqtDIUDDNK2UR/2m+JrbXorjYTirYfbkU5iMH+C/izzSEOFf5FAEzmnUYcbETmvrs2Jk2NqgGRrevNWPqo8jx8LKuX25qnDDnYBZQhxht9CwJB3sLAWTTZ7jJ9cCqN8JPaJpXWlOi1e3I+wo8LymwP0un/lJWwIDAQAB"; // 随机获取的 32位 AES密钥,注意长度要符合要求,可以自己随机生成 // String aesKey = AESKeyUtils.generateCustomAESKey(); String aesKey = "DMx3hkKhIReP5GGHoBGx751006331503"; System.err.println("AES密钥 = " + aesKey); // 组装请求数据,是JSON转字符串格式,如 String getInfoStr = "{\"current\":1,\"size\":100}"; JSONObject postInfo = new JSONObject(); postInfo.set("title", "加密添加标题Java代码调用"); postInfo.set("category", 1); postInfo.set("releaseTime", "2025-06-29 00:00:00"); String getInfoStr = JSONUtil.toJsonStr(postInfo); // 使用上一步随机生成的AES密钥对JSON转字符串格式请求的数据进行加密,即为data数据 String data = AesUtil.encryptToBase64(getInfoStr, aesKey); System.out.println("data数据 = " + data); // 上面是框架工具类加密,为了跨语言,我尝试分步加密,使用 hutool 工具类 // 首先获取由AES密钥生成的 AES 类,工作模式:CBC,填充模式:PKCS7,向量取密钥的前16位 AES hutoolAes = new AES("CBC", "PKCS7Padding", aesKey.getBytes(), aesKey.substring(0, 16).getBytes()); // 对请求字符串进行加密 获取加密的二进制数组 byte[] hutoolCryptByte = hutoolAes.encrypt(getInfoStr); // 对hutoolCryptByte进行base64编码为字符串 String hutoolData = Base64.getEncoder().encodeToString(hutoolCryptByte); System.err.println("hutool编码的data数据 = " + hutoolData); // 还有dataKey,dataKey是使用RSA公钥加密AES密钥的结果,RSA加密同样使用的是hutool工具类 RSA rsa = new RSA(null, cryptoPublicKey); // 公钥加密 byte[] encrypt = rsa.encrypt(aesKey, StandardCharsets.UTF_8, KeyType.PublicKey); // 加密后的byte[]是二进制数据 通常包含不可打印的字符 需要编码为Base64 String dataKey = Base64.getEncoder().encodeToString(encrypt); System.out.println("dataKey数据 = " + dataKey); // 获取token,无论是第三方使用参数获取、还是使用账号密码获取,获取token是一个比较私密的事情。不过获取token并没有加密,与之前获取token是一样的,因此没有撰写详细写加密解密方式 String token = AESKeyUtils.getToken(); System.out.println("token = " + token); // 发送请求 String cryptResult = org.springblade.core.http.HttpRequest.post("http://ywtb.dev.jzkg.cn/api/blade-desk/notice/submit") .addHeader("Blade-Auth", "bearer " + token) .addHeader("Authorization", "Basic c2FiZXIzOnNhYmVyM19zZWNyZXQ=") .addHeader("Blade-Requested-With", "BladeHttpRequest") .bodyJson(new JSONObject().set("data", hutoolData).set("dataKey", dataKey)) .execute().asString(); // cryptResult是调接口返回的密文 System.out.println("加密后的返回结果 = " + cryptResult); // 使用刚才生成的AES密钥进行解密,虽然发送请求的时候没有直接携带AES密钥,但是后台通过RSA私钥对dataKey进行解密获得AES密钥,将请求数据解密,查询完成数据之后又通过AES密钥对返回数据进行加密,所以可以直接使用刚才生成的AES密钥进行解密 String result = AesUtil.decryptFormBase64ToString(cryptResult, aesKey); System.out.println("解密后的返回结果 = " + result); // 上面是框架工具类解密,为了跨语言,我尝试分步解密,使用 hutool 工具类 // 使用刚才生成的hutoolAes进行解密,里面已经封装的将返回的加密文本转为Base64后进行解密,hutoolDecrypt已经是解密后的字节数组,可以直接转为字符串 byte[] hutoolDecrypt = hutoolAes.decrypt(cryptResult); String hutoolResult = new String(hutoolDecrypt, StandardCharsets.UTF_8); System.err.println("hutool解密后的返回结果 = " + hutoolResult); // 获得解密后的JSON字符串文本就可以转为JSON对象进行数据的操作了...... System.err.println("获得解密后的JSON字符串文本就可以转为JSON对象进行数据的操作了......"); } ``` 运行成功:  
王文彬
2025年8月28日 12:00
分享文档
收藏文档
上一篇
下一篇
微信扫一扫
复制链接
手机扫一扫进行分享
复制链接
Markdown文件
PDF文档
PDF文档(打印)
分享
链接
类型
密码
更新密码