springboot 前后端入参响应 加密解密

​由于有些项目需要对于安全要求比较高的情况下,可以使用这种方式对请求参数和返回参数进行加密解密的操作。

RequestBodyAdvice
主要作用是拦截请求的数据,对数据进行处理(RequestBodyAdvice仅对使用了@RqestBody注解的生效,因为它原理上还是AOP ,所以GET方法是不会操作的)
ResponseBodyAdvice
主要作用是拦截返回的数据,对数据进行处理

场景:例如加解密、打印日志

本质上是AOP拦截器

RequestBodyAdvice 和 ResponseBodyAdvice都需要搭配@RestControllerAdvice@ControllerAdvice使用

代码

maven依赖(自行查看项目中是否已经存在相关依赖了)

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.15</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.6.1</version>
        </dependency>
        <!--json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.45</version>
        </dependency>

自定义requestBody拦截器


/**
 * 拦截请求(可以对参数解密等操作)
 * RequestBodyAdvice仅对使用了@RqestBody注解的生效,因为它原理上还是AOP ,所以GET方法是不会操作的
 */
@ControllerAdvice
@Slf4j
public class RequestBody implements RequestBodyAdvice {

    //是否对请求拦截处理(根据实际情况可以写在配置文件中)
    private Boolean enable = true;

    //密钥(根据实际情况可以写在配置文件中)
    private final static String encryptKey = "abdel99999999";

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        log.info("【进入-RequestBody-supports】");
        //是否开启拦截
        if(!enable.equals(true)) {
            return false;
        }
        //排除get请求
        if(methodParameter.hasMethodAnnotation(GetMapping.class)) {
            return false;
        }
        return true;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        log.info("【进入-RequestBody-beforeBodyRead】");
        log.info("【拦截到的请求参数为:】" + inputMessage.toString());

        String s = null;
        String requestBodyStr = getRequestBodyStr(inputMessage.getBody());
        requestBodyStr = requestBodyStr.replaceAll("\\r\\n", "");
        JSONObject jsonObject = JSONObject.parseObject(requestBodyStr);
        String inputStr = jsonObject.getString("inputStr");
        try {
            s = EncrpytUtils.decryptDES(inputStr, encryptKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用解密后的数据,构造新的读取流
        InputStream rawInputStream = new ByteArrayInputStream(s.getBytes());
        return new HttpInputMessage() {
            @Override
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }

            @Override
            public InputStream getBody() throws IOException {
                return rawInputStream;
            }
        };
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        log.info("【进入-RequestBody-afterBodyRead】");
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        log.info("【进入-RequestBody-handleEmptyBody】");
        return null;
    }

    /**
     * reuqest body流数据转换为String
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static String getRequestBodyStr(InputStream inputStream) throws IOException {
        StringBuilder builder = new StringBuilder();
        if (!ObjectUtils.isEmpty(inputStream)) {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                builder.append(charBuffer, 0, bytesRead);
            }
        }else {
            builder.append("");
        }
        return builder.toString();

    }

}

自定义responseBody拦截器


/**
 * 它允许在 执行 @ResponseBody后自定义返回数据,或者将返回@ResponseEntity的 Controller Method在写入主体前使用HttpMessageConverter进行自定义操作。
 * 由此可见,它的作用范围为:使用@ResponseBody注解进行标记 返回@ResponseEntity
 *
 */
@RestControllerAdvice
@Slf4j
public class ResponseBody implements ResponseBodyAdvice {

    //是否对返回拦截处理
    private Boolean enable = true;

    private final static String encryptKey = "abdel99999999";

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        log.info("【进入-ResponseBody-supports】");
        if(enable.equals(true)) {
            return true;
        }
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        log.info("【进入-ResponseBody-beforeBodyWrite】");
        if(body == null) {
            return null;
        }
        String str;
        try {
            if(body instanceof String) {
                str = (String) body;
            }else {
                str = JSON.toJSONString(body);
            }
            String s = EncrpytUtils.encryptDES(str, encryptKey);
            log.info("【加密之后的数据:】" + s);
            return s.replaceAll("\\r\\n", "").replaceAll("\\n", "").replaceAll("\\r", "");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("【ResponseBody加密处理异常】");
            return "";
        }
    }
}

EncrpytUtils工具类


public class EncrpytUtils {

    /**
     * DES加密算法
     */
    public final static String ALGORITHM_DES = "DES";

    /**
     * 加密字符串(Java 8提供的Base64,要比sun.misc套件提供的还要快至少11倍,比Apache Commons Codec提供的还要快至少3倍)
     *
     * @param code       需要加密的字符串
     * @param encryptKey 对称密钥串
     * @throws Exception
     */
    public static String encryptDES(String code, String encryptKey) throws Exception {
        //java8提供的类(Base64)
        Base64.Encoder encoder = Base64.getEncoder();
        byte[] bytesMing = encryptDES(code.getBytes("UTF8"), encryptKey);
        return encoder.encodeToString(bytesMing);
    }

    /**
     * 解密字符串(Java 8提供的Base64,要比sun.misc套件提供的还要快至少11倍,比Apache Commons Codec提供的还要快至少3倍)
     *
     * @param code       需要解密的字符串1
     * @param encryptKey 对称密钥串
     * @throws Exception
     */
    public static String decryptDES(String code, String encryptKey) throws Exception {
        //java8提供的类(Base64)
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(code);
        byte[] bytesMing = decryptDES(decode, encryptKey);
        return new String(bytesMing, "UTF8");
    }


    /**
     * 加密
     *
     * @param bytes      明文字节
     * @param encryptKey 对称密钥串
     * @throws Exception
     */
    public static byte[] encryptDES(byte[] bytes, String encryptKey) throws Exception {
        Key key = generateKey(encryptKey);
        Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(bytes);
    }


    /**
     * 生成密钥
     *
     * @param encryptKey
     * @throws Exception
     */
    public static Key generateKey(String encryptKey) throws Exception {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM_DES);
        DESKeySpec keySpec = new DESKeySpec(encryptKey.getBytes());
        return keyFactory.generateSecret(keySpec);
    }

    /**
     * 解密
     *
     * @param bytes      密文字节
     * @param encryptKey 对称密钥串
     * @throws Exception
     */
    public static byte[] decryptDES(byte[] bytes, String encryptKey) throws Exception {
        Key key = generateKey(encryptKey);
        Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(bytes);
    }


    /**
     * 方便测试(正常情况下是前端加密请求参数,后端接收到请求参数进行解密操作,执行完逻辑之后,对返回的数据进行加密返回给前端,前端解密获取数据)
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        String test="{\"name\":\"1243\",\"age\":\"18\"}";
        String s = encryptDES(test, "abdel99999999");
        System.out.println("【加密之后数据:】" + s.replaceAll("\\r\\n",""));

        String a = "ERt7/Jenk6IUXqQ8lThdSC2/pa4ok2zHi00WmsZ/ejZSBl5tue0xPfom0lbznugFaKaS4U+CeK4qkzL58umRIkw2uBDKl/QvDbfK0povrUDmiCK2cbQmHvxSHl8eZNE/kWguLmPTBCkx4ukluDOfn5dRdovc6LmOnv+sH6SqSXT+8N8h5e3133LvQcxMeHJ5/fyJPfdUfomEcxrLkNIGRtZR/nJiGUNAxYRx0d6Ol2ziMB3rl9dwtlUg1h3WpbIQK13EsXK7yw6wIyGKYDJfZQ5y90MQTwJQ/fyJPfdUfolGgy60lKNvaNZR/nJiGUNAxYRx0d6Ol2xRbjUCuWOkkFUg1h3WpbIQK13EsXK7yw7/kUPCnnTkRjcqbJLsbi41qBXecwZ1295++KkaKFumbofsH9AUO0gLcmjVpmv6SJBJsK/B2mRK6ChA58AnNW9uBRzQiJwiy561MBtbId9rmCLjSw6YlZ6G3rAyZzJoMAhqph64pt+tc8/lZIUBWbhJobvpPD2Hf+kWIEVwFyfr2kF21rnbnxfi/FIeXx5k0T+RaC4uY9MEKZ46K/zylLpFKpot8yn1beN9kxRgMNlTmW4QresvktoCSF+qR1TXar+iWfnLPWVGxreTiMK95aJ0Ot2elSE/rkInJ+Po1xyN4knc4Ro5qgUr/IUM6wtDH0qbekH7+wN2kp0qMUJpq5Uh7R/2BqiMtIVDLRYyOzDFPFQV7RfRS/nvrOVAPRoTBNU8jkYiu5zbX5zdwnvHItKMK13EsXK7yw5SicWOT56KI4tM88TA0H8okvuh5K58C5JKGr5N8IDenKFUOmuvE6ATH3vHYZ8N92oo6+8QlEUPY6rihsJYMB8/77XN5L2c484=";
        String aa = decryptDES(a, "abdel99999999");
        System.out.println("【解密之后数据:】" + aa);
    }
}

controller层

@RequestMapping("user")
@RestController
@Slf4j
public class UserController {

    @PostMapping("selectUser2")
    public Object selectUser2(@RequestBody User user) {
        String s = JSON.toJSONString(user);
        System.out.println(s);
        log.info("【接收到的请求参数:】" + s);
        return "成功的返回数据了";
    }
}

你可能感兴趣的:(spring,boot,java,spring)