Encrypt-Thanos (springboot,springcloud http传输加解密框架,灭霸特别版 jdk1.8+支持)
,增加请求参数排序加密
git地址
一.功能介绍
-
springboot,springcloud项目快速开启前后端数据传输加密
-
提供多种加密方式(对称,非对称),支持自定义加密方式
-
集成简单,一个@EnableEncrypt注解即可开启全局加密规则,并支持@SeparateEncrypt类级别或方法级别细粒度控制加密
-
yml配置简单,并且提供提示描述
-
该框架推荐用在暴露给第三方接口加密传输场景中,关于有人提到避免重放攻击,可在传输中添加时间戳,唯一码方式避免
-
@SortSignEncryptjoin请求参数排序加密
注意:目前仅支持对application/json数据提交方式解密;表单提交不进行解密!
二.集成方式
https://search.maven.org/artifact/com.github.785175323/Encrypt-Thanos/1.1/jar
引入依赖~
<dependency>
<groupId>com.github.785175323</groupId>
<artifactId>Encrypt-Thanos</artifactId>
<version>1.1</version>
</dependency>
1.开启加密功能
- 编写yml配置文件开启功能
encrypt:
type: rsa #支持base64编码,aes对称加密,rsa非对称加密,custom自定义加密方式
privateKey: #rsa私钥
publicKey: #rsa公钥
debug: false #debug模式为true不开启加密
order: 1 #加密过滤器顺序号,不填则为0
secret: #aes加密方式秘钥
- 开启全局加密(伪代码)
此项必写,后面开启局部加密也要写
@EnableEncrypt
@SpringBootApplication
public class Application {}
- 开启局部加密方式:
@RestController
@SeparateEncrypt
public class Web {}
@PostMappint
@SeparateEncrypt
public Result get(@RequestBody Body body){}
2.集成自定义加密模式
- yml配置为自定义方式
encrypt:
type: custom
- 编写自定义加密实现
//实现EncryptHandler接口并注册到spring容器
@Component
public class EncryptCustom implements EncryptHandler {
//出参加密
@Override
public byte[] encode(byte[] content) {
return content;
}
//入参解密
@Override
public byte[] decode(byte[] content) {
return content;
}
}
3.生成RSA公钥及私钥
@Test
public void test() throws Exception {
RsaKeyEntity rsaKeys = RsaEncryptHandler.getRsaKeys();
String privateKey = rsaKeys.getPrivateKey();
String publicKey = rsaKeys.getPublicKey();
}
三.功能演示
1.集成RSA加密传输模式
- yml配置
server:
port: 8888
encrypt:
type: rsa
privateKey:
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAmsk/1OfysroyVE8vl9e........
publicKey:
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJrJP9Tn8rK6MlRP........
2.测试rsa加解密web接口:
实体类:
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
web接口:
@SeparateEncrypt
@RequestMapping("test")
public Object t3(@RequestBody(required = false) Student student) {
student.setAge(18);
student.setName("gaoyang2");
return student;
}
测试用例:
@Test
public void test() throws Exception {
Student s = new Student();
s.setAge(28);
s.setName("gaoyang");
RsaEncryptHandler rsaEncryptHandler = new RsaEncryptHandler();
rsaEncryptHandler.setPublicKey("MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ94IIx/5qw6KipB9+y62l7Z6sIrmhpA/lrL5cXslXP7Iwa4ZeX2xHJhXlNRi6Eyv3nx67O+1kbTIe6rJuE1fe0CAwEAAQ==");
rsaEncryptHandler.setPrivateKey("MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAn3ggjH/mrDoqKkH37LraXtnqwiuaGkD+WsvlxeyVc/sjBrhl5fbEcmFeU1GLoTK/efHrs77WRtMh7qsm4TV97QIDAQABAkBb9ArguUer/AYgQ9XQHZaZpxKlUDsV9HA2rugZjuhG7Zoq0J8sXZxtGt3GfS02OTJ5D7xHKAZ5FpLQpxwnS71JAiEAyilhNwKLSRmA0Ee/0s0EvKG7LJBjE1ymqXXGsX6s8mMCIQDJ8CP/LVzRIb1EuYow5nQ3C6EUh1TJUM98zKnlbcCXbwIgTZFXBb5qJyAr9r6w8XdMy/vaT50PBszT/c188XnDbjUCIQC3E9gOyPmVQJlvbSc0HjrOjOSE0Ay2V2VFJ+f/8PjiUQIhALCvioDG38FxtxWOFvN2kZvahrL33Ht23TnaZLJ70ceh");
byte[] bytes = rsaEncryptHandler.encryptByPublicKey(new ObjectMapper()
.writeValueAsString(s).getBytes("utf-8"), Base64Utils.decodeFromString(rsaEncryptHandler.getPublicKey()));
OkHttpClient c = new OkHttpClient();
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), bytes);
Request request = new Request.Builder()
.url("http://localhost:8080/test")
.post(requestBody)
.build();
Call call = c.newCall(request);
Response execute = call.execute();
byte[] bytes1 = execute.body().bytes();
byte[] decode = rsaEncryptHandler.decryptByPublicKey(bytes1, Base64Utils.decodeFromString(rsaEncryptHandler.getPublicKey()));
System.out.println(new String(new String(decode)));
}
控制台:
{"age":18,"name":"gaoyang2"}
四.springcloud集成openfeign调用加密接口报错解决:
1)生产者
@RestController
public class MyController implements MyService {
@Override
@SeparateEncrypt
@PostMapping("get")
public Student get(@RequestBody(required = false) Student student) {
if (student != null) {
System.out.println("i am producer+" + student.getName() + student.getAge());
}
Student s = new Student();
s.setAge(18);
s.setName("producer");
return s;
}
}
2)消费者
使用与生产者相同的方式加解密处理类进行编解码;
@FeignClient(value = "MECHANT", configuration = {MyClient.MyFeignConfig.class})
public interface MyClient extends MyService {
@Override
@PostMapping(value = "get", consumes = "application/json")
Student get(@RequestBody Student student);
@Configuration
class MyFeignConfig {
private static Gson gson = new Gson();
private static Base64EncryptHandler base64EncryptHandler = new Base64EncryptHandler();
class MyBase64DeCoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException, FeignException {
try (InputStream inputStream = response.body().asInputStream()) {
byte[] b = new byte[inputStream.available()];
inputStream.read(b);
inputStream.close();
byte[] decode = base64EncryptHandler.decode(b);
return gson.fromJson(new String(decode, "UTF-8"), type);
}
}
}
class MyBase64EnCoder implements Encoder {
@Override
public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
String s = gson.toJson(o, type);
byte[] encode = base64EncryptHandler.encode(s.getBytes());
requestTemplate.body(encode, Charset.forName("UTF-8"));
}
}
@Bean
public Decoder myBase64Decoder() {
return new MyBase64DeCoder();
}
@Bean
public Encoder myBase64Encoder() {
return new MyBase64EnCoder();
}
}
}
五.启用接口请求参数排序加密
1)注释和配置文件
application.properties:
{
encrypt.sortSignSecret=xx
}
@SortSignEncrypt(timeout = 6000,timeUnit = TimeUnit.MILLISECONDS)
@PostMapping("test")
public Object test(@RequestBody TestBody testbody,String sign ){
//TestBody{xx,xx,String timestamp}
}
2)必要条件
method=POST;contentType=application/json;
param: timestamp;sign
3)默认加密方法
在请求参数自然升序排序之后,
根据规则sign=md5(akey=value&timestamp=XX&zkey=value。。。&秘密=XX)
4)您可以自定义加密方法
sortsignencrypthandler接口和注册的自定义实现
5)其他配置
如果没有使用其他加密方法,则可以配置为debug,或者注释@separateencrypt的空方法