springboot aspect 对请求参数,返回数据加密
对客户端<--->服务端传输数据加密。
上送文件流不加密,其他信息加密。 返回信息加密。
切面的方式进行解密,不修改业务逻辑。
找到对应的方法,对应的参数,进行解密。
@Around("@annotation(com.jiayingsoft.scip.annotation.ScipSecureityMethodAtn)")
public Object run(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature methodSignature = (MethodSignature) (pjp.getSignature());
Method method = methodSignature.getMethod();
String secret = fetchAppsecret();
Map<Parameter, Object> map = getParameterAndValue(pjp);
for (Iterator<Map.Entry<Parameter, Object>> iterator = map.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Parameter, Object> row = iterator.next();
if (row.getKey().isAnnotationPresent(ScipSecurityParameterAtn.class)) {
Object obj = row.getValue();
if (obj != null && obj.toString().trim() != "") {
String desStr = AESUtil.decrypt(obj.toString(), secret);
row.setValue(desStr);
}
}
}
Object obj = pjp.proceed(map.values().toArray());
// if (obj instanceof String) {
// return AESUtil.encrypt(obj.toString(), secret);
// }
// if (obj instanceof R) {
// R r = ((R<?>) obj);
// if (r.getData() != null) {
// r.setData(AESUtil.encrypt(JSON.toJSONString(r.getData()), secret));
// }
// }
return obj;
}
在加密返回信息时,碰到问题。
加密后,信息是字符串,但是在controller层面不愿意写死返回类型,如果controller 返回返回的不是字符串,那么springboot 按照返回类型序列化,由于这里我把返回类型改成字符串,故springboot 序列化失败。
解决方法
1:controller--function 返回String 类型(写的太死了,拓展性不好)
2:核心数据加密,外面包一层,这样springboot 序列化时不会报错,但是前端解密稍复杂。
bing 上搜索后,发现可以继承 ResponseBodyAdvice 用 ControllerAdvice 在controller层做切面,在 beforeBodyWrite() 方法上做加密,当然controller 必须是@ResponseBody
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
String originString = JSON.toJSONString(body);
String encryptBase64String = AESUtil.encrypt(originString, ScipSecureitAspect.fetchAppsecret());
return encryptBase64String;
}
如上返回
前端解密失败,后发现返回的字符串 多了引号,服务端显示返回长度是100字符,前端收到102字符
解决方法:
1:前端处理,先去掉引号,再解密 (太奇怪,为什么要这么做)
2 :覆盖MappingJackson2HttpMessageConverter 的 withInternal 方法 (可能会影响其他业务)、
后面stackoverflow.com发现这个方法,成功解决问题 链接
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
String originString = JSON.toJSONString(body);
String encryptBase64String = AESUtil.encrypt(originString, ScipSecureitAspect.fetchAppsecret());
response.getHeaders().set("content-type", "text/plain;charset=UTF-8");
try (OutputStream stream = response.getBody()) {
stream.write(encryptBase64String.getBytes("utf-8"));
stream.flush();
} catch (IOException e) {
log.error("failed to send message:"+e.getMessage());
e.printStackTrace();
}
return null;
}
把流直接写入response。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话