在我们的应用程序中,我们必须为每个请求和响应加密/解密Json属性值(而不是属性名称)。
例如,
{"userName":"encrypted value", "email":"encrypted value"}
我们使用Sprint boot 1.3,我们使用 @RequestBody 和 @ResponseBody 注释将请求json与对象绑定,并将响应对象序列化为JSON。
我们不想要在我们的每个控制器方法中调用加密/解密方法。有没有什么办法可以指示sprint在绑定请求对象之前解密json值?同样,在将响应对象字段值转换为json之前对其进行加密?或者定制杰克逊可以帮助我们吗?
谢谢!
答案 0 :(得分:10)
您可以编写自己的http消息转换器。由于您使用的是弹簧启动,因此非常简单:只需从AbstractHttpMessageConverter
扩展自定义转换器,并使用@Component
注释标记该类。
来自spring docs:
只需在Spring Boot上下文中添加该类型的bean,即可添加其他转换器。如果你添加的bean是默认包含的类型(比如MappingJackson2HttpMessageConverter用于JSON转换),那么它将替换默认值。
这是一个简单的例子:
@Component
public class Converter extends AbstractHttpMessageConverter<Object> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
@Inject
private ObjectMapper objectMapper;
public Converter(){
super(MediaType.APPLICATION_JSON_UTF8,
new MediaType("application", "*+json", DEFAULT_CHARSET));
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
@Override
protected Object readInternal(Class<? extends Object> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(decrypt(inputMessage.getBody()), clazz);
}
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write(encrypt(objectMapper.writeValueAsBytes(o)));
}
private InputStream decrypt(InputStream inputStream){
// do your decryption here
return inputStream;
}
private byte[] encrypt(byte[] bytesToEncrypt){
// do your encryption here
return bytesToEncrypt;
}
}
答案 1 :(得分:0)
好的,所以我使用了@eparvan的答案,并做了很少的修改。
我正在以类似这种方式在“数据”对象中获取加密格式的请求参数,并以与数据对象相同的方式发送加密的响应。
参考回复: {“ data”:“ requestOrResponseInEncryptedUsingPrivateKey”}
@Component
public class Converter extends AbstractHttpMessageConverter<Object> {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
@Autowired
private ObjectMapper objectMapper;
public Converter() {
super(MediaType.APPLICATION_JSON,
new MediaType("application", "*+json", DEFAULT_CHARSET));
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
@Override
protected Object readInternal(Class<? extends Object> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(decrypt(inputMessage.getBody()), clazz);
}
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write(encrypt(objectMapper.writeValueAsBytes(o)));
}
/**
* requests params of any API
*
* @param inputStream inputStream
* @return inputStream
*/
private InputStream decrypt(InputStream inputStream) {
//this is API request params
StringBuilder requestParamString = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) {
int c;
while ((c = reader.read()) != -1) {
requestParamString.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
//replacing /n if available in request param json string
//reference request: {"data":"thisisencryptedstringwithexpirytime"}
JSONObject requestJsonObject = new
JSONObject(requestParamString.toString().replace("\n", ""));
String decryptRequestString = EncryptDecrypt.decrypt(requestJsonObject.getString("data"));
System.out.println("decryptRequestString: " + decryptRequestString);
if (decryptRequestString != null) {
return new ByteArrayInputStream(decryptRequestString.getBytes(StandardCharsets.UTF_8));
} else {
return inputStream;
}
} catch (JSONException err) {
Log.d("Error", err.toString());
return inputStream;
}
}
/**
* response of API
*
* @param bytesToEncrypt byte array of response
* @return byte array of response
*/
private byte[] encrypt(byte[] bytesToEncrypt) {
// do your encryption here
String apiJsonResponse = new String(bytesToEncrypt);
String encryptedString = EncryptDecrypt.encrypt(apiJsonResponse);
if (encryptedString != null) {
//sending encoded json response in data object as follows
//reference response: {"data":"thisisencryptedstringresponse"}
Map<String, String> hashMap = new HashMap<>();
hashMap.put("data", encryptedString);
JSONObject jsob = new JSONObject(hashMap);
return jsob.toString().getBytes();
} else
return bytesToEncrypt;
}
}
这是我的EncryptDecrypt类,正在进行加密和解密
class EncryptDecrypt {
static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(Constants.Encryption.INIT_VECTOR.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new
SecretKeySpec("PRIVATE_KEY_FOR_ENCRYPTION_OR_DECRYPTION"
.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
byte[] original = Base64.getEncoder().encode(encrypted);
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(Constants.Encryption.INIT_VECTOR
.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new SecretKeySpec("PRIVATE_KEY_FOR_ENCRYPTION_OR_DECRYPTION".
getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
您完成了!