• Spring对JSON请求加解密


    Spring中处理JSON请求通常使用@RequestBody和@ResponseBody注解,针对JSON请求加解密和过滤字符串,Spring提供了RequestBodyAdvice和ResponseBodyAdvice两个接口 
    具体使用 
    1、解密:

    
    import com.hive.util.AESOperator;
    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.Type;
    
    /**
     * 请求数据解密
     */
    @ControllerAdvice(basePackages = "com.hive")
    public class MyRequestBodyAdvice implements RequestBodyAdvice {
        private final static Logger logger = LoggerFactory.getLogger(MyResponseBodyAdvice.class);
        @Override
        public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            return true;
        }
    
        @Override
        public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            return body;
        }
    
        @Override
        public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
            try {
                return new MyHttpInputMessage(inputMessage);
            } catch (Exception e) {
                e.printStackTrace();
                return inputMessage;
            }
        }
    
        @Override
        public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            return body;
        }
    
        class MyHttpInputMessage implements HttpInputMessage {
            private HttpHeaders headers;
    
            private InputStream body;
    
            public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
                this.headers = inputMessage.getHeaders();
                this.body = IOUtils.toInputStream(AESOperator.getInstance().decrypt(IOUtils.toString(inputMessage.getBody(), "UTF-8")), "UTF-8");
            }
    
            @Override
            public InputStream getBody() throws IOException {
                return body;
            }
    
            @Override
            public HttpHeaders getHeaders() {
                return headers;
            }
        }
    }

    2、加密:

    package com.hive.core.json;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.hive.util.AESOperator;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    /**
     * 返回数据加密
     */
    @ControllerAdvice(basePackages = "com.hive")
    public class MyResponseBodyAdvice implements ResponseBodyAdvice {
        private final static Logger logger = LoggerFactory.getLogger(MyResponseBodyAdvice.class);
        private final static String KEY = "!QA2Z@w1sxO*(-8L";
    
        @Override
        public boolean supports(MethodParameter returnType, Class converterType) {
            return true;
        }
    
        @Override
        public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
            boolean encode = false;
            if (returnType.getMethod().isAnnotationPresent(SerializedField.class)) {
                //获取注解配置的包含和去除字段
                SerializedField serializedField = returnType.getMethodAnnotation(SerializedField.class);
                //是否加密
                encode = serializedField.encode();
            }
            if (encode) {
                logger.info("对方法method :" + returnType.getMethod().getName() + "返回数据进行加密");
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
                    return AESOperator.getInstance().encrypt(result);
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return body;
        }
    }
    

    注解类:

    package com.hive.core.json;
    
    import org.springframework.web.bind.annotation.Mapping;
    
    import java.lang.annotation.*;
    
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface SerializedField {
        /**
         * 是否加密
         * @return
         */
        boolean encode() default true;
    }
    }

    这里写图片描述 
    默认是true,我这边使用false。注解类中还可以定义需要过滤的字符串

    AES加密类

    package com.hive.util;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    /**
     * AES CBC加密
     */
    public class AESOperator {
        /*
         * 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
         */
        private String KEY = "!QA2Z@w1sxO*(-8L";
        private String VECTOR = "!WFNZFU_{H%M(S|a";
        private static AESOperator instance = null;
    
        private AESOperator() {
    
        }
    
    
        public static AESOperator getInstance() {
            return Nested.instance;
        }
        //于内部静态类只会被加载一次,故该实现方式时线程安全的!
        static class Nested {
            private static AESOperator instance = new AESOperator();
        }
    
        /**
         * 加密
         *
         * @param content
         * @return
         * @throws Exception
         */
        public String encrypt(String content) throws Exception {
            return encrypt(content, KEY, VECTOR);
        }
        /**
         * 加密
         *
         * @param content
         * @return
         * @throws Exception
         */
        public String encrypt(String content,String key) throws Exception {
            return encrypt(content, key, VECTOR);
        }
    
        /**
         * 加密
         *
         * @param content
         * @param key
         * @param vector
         * @return
         * @throws Exception
         */
        public String encrypt(String content, String key, String vector) throws Exception {
            if (key == null) {
                return null;
            }
            if (key.length() != 16) {
                return null;
            }
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
            return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
        }
    
        /**
         * 解密
         *
         * @param content
         * @return
         * @throws Exception
         */
        public String decrypt(String content) throws Exception {
            return decrypt(content, KEY, VECTOR);
        }
        /**
         * 解密
         *
         * @param content
         * @return
         * @throws Exception
         */
        public String decrypt(String content,String key) throws Exception {
            return decrypt(content, key, VECTOR);
        }
        /**
         * 解密
         *
         * @param content
         * @param key
         * @param vector
         * @return
         * @throws Exception
         */
        public String decrypt(String content, String key, String vector) throws Exception {
            try {
                if (key == null) {
                    return null;
                }
                if (key.length() != 16) {
                    return null;
                }
                SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
                IvParameterSpec iv = new IvParameterSpec(vector.getBytes());
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] encrypted1 = new BASE64Decoder().decodeBuffer(content);// 先用base64解密
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original, "UTF-8");
                return originalString;
            } catch (Exception ex) {
                return null;
            }
        }
    
        public static void main(String[] args) throws Exception {
            // 需要加密的字串
            String cSrc = "我爱你";
    
            // 加密
            long lStart = System.currentTimeMillis();
            String enString = AESOperator.getInstance().encrypt(cSrc,"!QA2Z@w1sxO*(-8L");
            System.out.println("加密后的字串是:" + enString);
    
            long lUseTime = System.currentTimeMillis() - lStart;
            System.out.println("加密耗时:" + lUseTime + "毫秒");
            // 解密
            lStart = System.currentTimeMillis();
            String DeString = AESOperator.getInstance().decrypt(enString);
            System.out.println("解密后的字串是:" + DeString);
            lUseTime = System.currentTimeMillis() - lStart;
            System.out.println("解密耗时:" + lUseTime + "毫秒");
        }
    
    }
  • 相关阅读:
    HashMap和Hashtable及HashSet的区别
    Android获取系统的时间
    Android的布局属性
    ListView 在代码里设置margin
    如何用Vue自己实现一个message提示插件
    JS获取最近三个月日期范围
    css实现表单label文字两端对齐
    my utils
    Vue 路由&组件懒加载(按需加载)
    C# 通过window消息控制指定控件的scroll滚动
  • 原文地址:https://www.cnblogs.com/myibm/p/7244806.html
Copyright © 2020-2023  润新知