最近项目用到springcloud 的组件zuul 作为网关做统一的请求转发,有一个需求在网关模块处理请求过来的参数进行解密然后再转发到后续模块,后续模块处理完毕再转回网关处理加密然后返回前端的过程。

   解密:在网关中加decodeFilter,在run方法中处理,处理解密主要针对get方式的url参数以及类似post请求的requestBody的参数进行处理。

加密:在网关中加encodeFilter,在run方法中处理加密操作

下面直接上代码:

一). 解密主要针对get和pots方式的请求参数处理

1)get 方式的处理方式,主要逻辑是通过request获取参数集合,然后对集合参数解密再统一封装再重写get request的queryString

/**
     * 对请求如get请求的参数的value aes方式解密 并重新封装请求参数
     * @param ctx
     * @throws Exception
     */
    private void getAesDecrypt(RequestContext ctx) throws Exception {
        HttpServletRequest request = ctx.getRequest();
        Map<String, String[]> paramMap = request.getParameterMap();
        String key = getAesKey(request);
        StringBuilder decryptBuilder = new StringBuilder();
        for (String s : paramMap.keySet()) {

            String value = paramMap.get(s)[0];
            try {
                log.info("key:{},......before decode value: {}",s,value);
                byte[] decryptData = AESUtils.decrypt(AESUtils.parseHexStr2Byte(value), key);
                decryptBuilder.append(s)
                        .append("=" )
                        .append( new String(decryptData, CommonConstants.CHARSET_UTF_8))
                        .append("&");
            }catch (Exception e){
                log.error(e.getMessage());
                throw new IcarException(CommonConstants.REQUEST_CONTENT_DECRYPTION_FAILED,CommonConstants.REQUEST_CONTENT_DECRYPTION_FAILED_MESSAGE);

            }

        }
        String decryptTemp = "";
        if (StringUtils.isNotBlank(decryptBuilder.toString())) {
            decryptTemp = decryptBuilder.substring(0, decryptBuilder.length() - 1); ;
        }
        String decryptString = decryptTemp;
        refactorGetRequest(ctx,decryptString);
    }
	
	 /**
     * 重新构造 get 方式的request 参数
     * @param ctx
     * @param decryptString
     */
    private void refactorGetRequest(RequestContext ctx,String decryptString){
        ctx.setRequest(new HttpServletRequestWrapper(ctx.getRequest()) {

            @Override
            public String getQueryString() {

                return decryptString;
            }

            @Override
            public String getContentType() {

                return MediaType.APPLICATION_JSON_VALUE;
            }
        });
    }

2.post 方式的reuqestBody 参数,主要逻辑是request获取requestBody,然后进行解密再重写requestBody

/**
     * 对请求的requestBody内容aes方式解密 ,如post,put 请求的requestBody
     * @param ctx RequestContext
     * @throws Exception
     */
    private void requestBodyAesDecrypt(RequestContext ctx) throws Exception {
        HttpServletRequest request = ctx.getRequest();
        ServletInputStream servletInputStream = request.getInputStream();
        String requestParam = StreamUtils
                .copyToString(servletInputStream, Charset.forName(CommonConstants.CHARSET_UTF_8));
        String key = getAesKey(request);
        byte[] decryptData = new byte[]{};
        if(StringUtils.isNotBlank(requestParam)){
            try {
                log.info("before decode :{}",requestParam);
                decryptData = AESUtils.decrypt(AESUtils.parseHexStr2Byte(requestParam), key);
            }catch (Exception e){
                log.error(e.getMessage());
                throw new IcarException(CommonConstants.REQUEST_CONTENT_DECRYPTION_FAILED,CommonConstants.REQUEST_CONTENT_DECRYPTION_FAILED_MESSAGE);
            }

        }
        refactorPostRequest(ctx,decryptData);
    }

/**
     * 重新构造 post 的request 参数
     * @param ctx
     * @param decryptData
     */
    private void refactorPostRequest(RequestContext ctx, byte[] decryptData){

   //  此句是改变request的content-type为json方式   ctx.addZuulRequestHeader(HeaderCode.CONTENT_TPPE,MediaType.APPLICATION_JSON_VALUE);


        ctx.setRequest(new HttpServletRequestWrapper(ctx.getRequest()) {
            @Override
            public ServletInputStream getInputStream() throws IOException {

                return new ServletInputStreamWrapper(decryptData);
            }

            @Override
            public int getContentLength() {

                return decryptData.length;
            }

            @Override
            public long getContentLengthLong() {

                return decryptData.length;
            }



        });
    }

二). 加密操作

/**
     * 对返回body进行aes加密
     */
    private void aesEncode(RequestContext ctx) throws Exception {

        try {
			InputStream inputStream = ctx.getResponseDataStream();
            String response = StreamUtils.copyToString(inputStream, Charset.forName(CommonConstants.CHARSET_UTF_8));
            //aes 加密
            log.info("before aes encode response: {}", response);
            HttpServletRequest request = ctx.getRequest();
            String key = getAesKey(request);
            byte[] encodeResult = AESUtils.encrypt(response.getBytes(), key);
            String result = AESUtils.parseByte2HexStr(encodeResult);
            log.info("aes encode result ={}", result);
            ctx.setResponseBody(result);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new IcarException(CommonConstants.AES_ENCODE_FAILED, CommonConstants.AES_ENCODE_FAILED_MESSAGE);
        }

    }

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐