springboot aspect 对请求参数,返回数据加密

发布时间 2023-05-25 17:38:42作者: wangjin_1

 

     对客户端<--->服务端传输数据加密。

    上送文件流不加密,其他信息加密。   返回信息加密。

  切面的方式进行解密,不修改业务逻辑。

     找到对应的方法,对应的参数,进行解密。

  @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。