Springboot使用filter对response内容进行加密

一、编写加密类(AES)

/**
 * aes加密解密
 */
public class AesEncryptUtils {

    //参数分别代表 算法名称/加密模式/数据填充方式
    private static String algorithmstr = "AES/ECB/PKCS5Padding";



    public static String getAlgorithmstr() {
        return algorithmstr;
    }


    /**
     * 加密
     * @param content 加密的字符串
     * @param encryptKey key值
     * @return
     * @throws Exception
     */
    public static String encrypt(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(algorithmstr);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
        byte[] b = cipher.doFinal(content.getBytes("utf-8"));
        return Base64.encodeBase64String(b);
    }

    /**
     * 解密
     * @param encryptStr 解密的字符串
     * @param decryptKey 解密的key值
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptStr, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(algorithmstr);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        byte[] encryptBytes = Base64.decodeBase64(encryptStr);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }

    public static void main(String[] args) throws Exception{
        String str  = "pp2bQLjabobRWp2T5Ro5/GlqWCigmkwHYnrOK11VZkTkIA2hSwnEi1sijfTV6Ozd/";
        System.out.println(decrypt(str,"f8db034bda44rtkb"));
    }
}

二、编写Filter类

/**
 * 过滤器拦截请求,实现加密解密功能
 *
 * @Component 将此Filter交给Spring容器管理
 * @WebFilter 通过WebFilter进行Filter声明,这样容器在进行部署的时候就会处理该Filter
 *
 */
@Component
public class EncryptFilter implements Filter {
    Logger log = LoggerFactory.getLogger(this.getClass());
    @Value("${admin.encrypt.excludeUrl}")
    private String ignoreStr;
    private String[] ignoreArr;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
    /**
     * 有错误相应返回-44
     *
     * @param response
     * @throws IOException
     */
    private void getFailResponse(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        out = response.getWriter();
//        out.write("{\n" +
//                "    \"status\":"+ Constant.ENCRYPT_FAIL +",\n" +
//                "    \"message\": null,\n" +
//                "    \"data\": []\n" +
//                "}");
        //加密后的错误消息
        out.write("+D+JO8tuwkrNbxnTTLdqStifmQceT+LlYETnIG/JZKrbAn+gIiqIp3VbzBV1y6R8B7aY53VM2xHa7cY3Osbnqw==");
        out.flush();
        out.close();
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        if(ignoreArr==null){
            ignoreArr = ignoreStr.split(",");
        }
        HttpServletRequest HttpRequest=(HttpServletRequest)request;
        HttpServletResponse HttpResponse=(HttpServletResponse)response;
        boolean flag=isIgnore(HttpRequest,ignoreArr);
        if(flag) {
            try {
                chain.doFilter(HttpRequest, HttpResponse);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ServletException e) {
                e.printStackTrace();
            }
        }else{
            try{
                //响应处理  包装响应对象 res 并缓存响应数据
                ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
                //执行业务逻辑 交给下一个过滤器或servlet处理
                chain.doFilter(request, responseWrapper);
                byte[] resData = responseWrapper.getResponseData();
                //设置响应内容格式,防止解析响应内容时出错
//            responseWrapper.setContentType("text/plain;charset=UTF-8");
                //加密响应报文并响应
                String encryptBASE64 = AesEncryptUtils.encrypt(new String(resData),Constant.ENCRYPT_STR);
                PrintWriter out = response.getWriter();
                out.print(encryptBASE64);
                out.flush();
                out.close();

            }catch(Exception e){
                try {
                    getFailResponse((HttpServletResponse)response);
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
                e.printStackTrace();
            }
        }
}

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * 哪些路径不处理
     * @param request
     * @param strArr
     * @return
     */
    public boolean isIgnore(HttpServletRequest request,String[] strArr) {
        String path=request.getRequestURI();
        for(String ignore:strArr) {
            if(path.contains(ignore)) {
                return true;
            }
        }
        return false;
    }
}

下图是对应的application.properties中的配置
在这里插入图片描述
其中用到了两个工具类
RequestWrapper

/**
 * @Description: 请求包装类
 * @Date: 2020/5/26 16:29
 */
public class RequestWrapper extends HttpServletRequestWrapper {

    private String requestBody = null;
    //请求体
    private HttpServletRequest req = null;
    //    private final byte[] body;//保存流的字节数组
    private final Map<String, String> reqHeaders=new HashMap<>();


    public RequestWrapper(HttpServletRequest request) throws IOException {

        super(request);
        this.req = request;
//        this.reqHeaders = new HashMap<String, String>();
//        String sessionStream = getRequestBodyStr(request);//读取流中的参数
//        body = sessionStream.getBytes(Charset.forName("UTF-8"));
    }

    public RequestWrapper(HttpServletRequest request, String requestBody) {
        super(request);
        this.requestBody = requestBody;
        this.req = request;
//        this.reqHeaders = request.get;
    }

    /**
     * @Description: 获取请求body
     * @Date: 2020/5/26 10:31
     * @Param: [request]
     * @Return: java.lang.String
     */
    public String getRequestBodyStr(final ServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = cloneInputStream(request.getInputStream());
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
        return sb.toString();
    }

    /**
     * @Description: 复制输入流
     * @Param: [inputStream]
     * @Return: java.io.InputStream
     */
    public InputStream cloneInputStream(ServletInputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) > -1) {
            byteArrayOutputStream.write(buffer, 0, len);
        }
        byteArrayOutputStream.flush();
        InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        return byteArrayInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody.getBytes(req.getCharacterEncoding()));

        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }


    /**
     * 添加header的名称和值
     *
     * @param name
     * @param value
     */
    public void addHeader(String name, String value) {
        reqHeaders.put(name, value);
    }

    @Override
    public String getHeader(String name) {
//        log.info("getHeader --->{}", name);
        String headerValue = super.getHeader(name);
        if (reqHeaders.containsKey(name)) {
            headerValue = reqHeaders.get(name);
        }
        return headerValue;
    }

    /**
     * 得到headers的名称
     */
    @Override
    public Enumeration<String> getHeaderNames() {
        List<String> names = Collections.list(super.getHeaderNames());
        for (String name : reqHeaders.keySet()) {
            names.add(name);
        }
        return Collections.enumeration(names);
    }

    @Override
    public Enumeration<String> getHeaders(String name) {
//        log.info("getHeaders name --->>>>>>{}", name);
        List<String> values = Collections.list(super.getHeaders(name));
//        log.info("getHeaders value --->>>>>>{}", values);
        if (reqHeaders.containsKey(name)) {
            values = Arrays.asList(reqHeaders.get(name));
        }
        return Collections.enumeration(values);
    }
}

ResponseWrapper

/**
 * @Description: 响应包装类
 * @Date: 2020/5/26 16:29
 */
public class ResponseWrapper extends HttpServletResponseWrapper {

    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream out = null;
    private PrintWriter writer = null;

    public ResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
        buffer = new ByteArrayOutputStream();// 真正存储数据的流
        out = new WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer,this.getCharacterEncoding()));
    }

    /** 重载父类获取outputstream的方法 */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    /** 重载父类获取writer的方法 */
    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
        return writer;
    }

    /** 重载父类获取flushBuffer的方法 */
    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }

    @Override
    public void reset() {
        buffer.reset();
    }

    /** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
    public byte[] getResponseData() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    /** 内部类,对ServletOutputStream进行包装 */
    private class WapperedOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos = null;

        public WapperedOutputStream(ByteArrayOutputStream stream)
                throws IOException {
            bos = stream;
        }

        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }

        @Override
        public void write(byte[] b) throws IOException {
            bos.write(b, 0, b.length);
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }
    }


}

三、写配置类

@Configuration
public class WebConfiguration {
    @Autowired
    private EncryptFilter encryptFilter;
    @Bean
    public FilterRegistrationBean registFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(encryptFilter);
        registration.addUrlPatterns("/*");
        registration.setName("EncryptFilter");
        registration.setOrder(1);
//        registration.setEnabled(false);
        return registration;

    }
    
    //做跨域处理,跟这个filter没关系
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowCredentials(true)
                        .allowedMethods("*")
                        .allowedHeaders("*")
                        .maxAge(3600);
            }
        };
    }
}

参考文章
1.配置过滤器对某个路径下的资源不进行拦截
2.在springBoot项目内自写的一个过滤器(对请求响应信息做加解密处理,见案例)
3.SpringBoot前后端数据传输加密

猜你喜欢

转载自blog.csdn.net/temp_44/article/details/107762290
今日推荐