1:创建加解密注解注解(对于拦截路径上全部采用数据加解密处理,如果有部分接口不需要加解密处理的话,在方法上或者类上加上此注解即可不做加解密处理)

package com.hars.common.infrastructure.validation.security;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 加解密注解
 *
 * @author Huangbigao
 * @date 2020/8/29 11:02
 */
@Documented
@Target({ElementType.METHOD, ElementType.TYPE,})
@Retention(RetentionPolicy.RUNTIME)
public @interface CryptoDecryptionSecurity {

    /**
     * 是否加解密,默认加解密
     *
     * @return
     */
    boolean cryptoDecryption() default true;

    /**
     * 是否进行request 解密,默认进行解密
     *
     * @return
     */
    boolean requestDecryption() default true;

    /**
     * 是否对输出结果进行加密,默认进行加密
     *
     * @return
     */
    boolean responseCrypto() default true;
}

ps:注解使用

 	@CryptoDecryptionSecurity(responseCrypto = false)
    @ApiOperation(value = "微信公众号验证业务处理接口")
    @GetMapping(value = "/handle/{appid}", produces = "text/plain;charset=utf-8")
    public String authHandle(@PathVariable String appid,
                             @RequestParam(name = "signature", required = false) String signature,
                             @RequestParam(name = "timestamp", required = false) String timestamp,
                             @RequestParam(name = "nonce", required = false) String nonce,
                             @RequestParam(name = "echostr", required = false) String echostr,
                             HttpServletRequest request) {

        return weChatMpService.authHandle(appid, signature, timestamp, nonce, echostr, request);
    }

2:创建request解密类

package com.hars.common.infrastructure.utils.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.hars.common.infrastructure.utils.aes.AesUtil;
import com.hars.common.infrastructure.utils.http.HttpContextUtil;
import com.hars.common.infrastructure.utils.string.StringUtil;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.util.Assert;

/**
 * @author Huangbigao
 * @date 2020/8/29 10:12
 */
public class DecryptionRequestUtil extends HttpServletRequestWrapper {

    private static final String APPLICATION_JSON = "application/json";
    /**
     * 所有参数的Map集合
     */
    private Map<String, String[]> parameterMap;
    /**
     * 输入流
     */
    private InputStream inputStream;
    private final boolean valueValid = true;

    public DecryptionRequestUtil(HttpServletRequest request, String password) {
        super(request);

        String encrypt;
        String contentType = request.getHeader("Content-Type");

        if (contentType != null && contentType.contains(APPLICATION_JSON)) {
            //json
            String bodyStr = HttpContextUtil.getBodyString(request);
            if (StringUtil.isBlank(bodyStr)){
                return;
            }
            encrypt = (String) JSON.parseObject(bodyStr).get("encrypt");
        } else {
            // url
            encrypt = request.getParameter("encrypt");
        }

        String jsonData = AesUtil.decrypt(encrypt, password);
        if (StringUtil.isBlank(jsonData)){
            return;
        }

        if (contentType != null && contentType.contains(APPLICATION_JSON)) {
            if (this.inputStream == null) {
                this.inputStream = new DecryptionInputStream(new ByteArrayInputStream(jsonData.getBytes()));
            }
        }
        parameterMap = buildParams(jsonData);
    }

    private Map<String, String[]> buildParams(String src) {
        Map<String, String[]> map = new HashMap<>();
        Map<String, String> params = JSONObject.parseObject(src, new TypeReference<Map<String, String>>() {
        });
        for (String key : params.keySet()) {
            map.put(key, new String[]{params.get(key)});
        }
        return map;
    }

    @Override
    public String getParameter(String name) {
        String[] values = getParameterMap().get(name);
        if (valueValid){
            if (values != null) {
                return (values.length > 0 ? values[0] : null);
            }
            return super.getParameter(name);
        }else {
            return (values.length > 0 ? values[0] : null);
        }
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = getParameterMap().get(name);

        if (valueValid){
            if (values != null) {
                return values;
            }
            return super.getParameterValues(name);
        }else {
            return values;
        }
    }

    @Override
    public Enumeration<String> getParameterNames() {
        Map<String, String[]> multipartParameters = getParameterMap();
        if (valueValid){
            if (multipartParameters.isEmpty()) {
                return super.getParameterNames();
            }
        }else {
            if (multipartParameters.isEmpty()) {
                return null;
            }
        }

        Set<String> paramNames = new LinkedHashSet<>();
        Enumeration<String> paramEnum = super.getParameterNames();
        while (paramEnum.hasMoreElements()) {
            paramNames.add(paramEnum.nextElement());
        }
        paramNames.addAll(multipartParameters.keySet());
        return Collections.enumeration(paramNames);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        if (valueValid){
            return parameterMap == null ? super.getParameterMap() : parameterMap;
        }else {
            return parameterMap == null ? new HashMap<>() : parameterMap;
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (valueValid){
            return this.inputStream == null ? super.getInputStream() : (ServletInputStream) this.inputStream;
        }else {
            return this.inputStream == null ? null : (ServletInputStream) this.inputStream;
        }
    }

    /**
     * 自定义ServletInputStream
     */
    private class DecryptionInputStream extends ServletInputStream {

        private final InputStream sourceStream;

        /**
         * Create a DelegatingServletInputStream for the given source stream.
         *
         * @param sourceStream the source stream (never {@code null})
         */
        public DecryptionInputStream(InputStream sourceStream) {
            Assert.notNull(sourceStream, "Source InputStream must not be null");
            this.sourceStream = sourceStream;
        }

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

        @Override
        public void close() throws IOException {
            super.close();
            this.sourceStream.close();
        }

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

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

        @Override
        public void setReadListener(ReadListener readListener) {

        }
    }
}

3:创建response加密类

package com.hars.common.infrastructure.utils.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * @author Huangbigao
 * @date 2020/8/29 13:11
 */
public class ResponseWrapperUtil extends HttpServletResponseWrapper {

    private ByteArrayOutputStream buffer;
    private ServletOutputStream out;

    public ResponseWrapperUtil(HttpServletResponse httpServletResponse) {
        super(httpServletResponse);
        buffer = new ByteArrayOutputStream();
        out = new WrapperOutputStream(buffer);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
    }

    public byte[] getContent() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    private static class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos;

        WrapperOutputStream(ByteArrayOutputStream bos) {
            this.bos = bos;
        }

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

        @Override
        public boolean isReady() {

            // TODO Auto-generated method stub
            return false;

        }

        @Override
        public void setWriteListener(WriteListener arg0) {

            // TODO Auto-generated method stub

        }
    }
}

5:创建AES加密工具类

package com.hars.common.infrastructure.utils.aes;

import com.hars.common.infrastructure.utils.string.StringUtil;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import lombok.extern.slf4j.Slf4j;

/**
 * AES 加解密 工具类
 *
 * @author Huangbigao
 * @date 2020/8/28 15:17
 */
@Slf4j
public class AesUtil {

    /**
     * AES解密
     *
     * @param content  密文
     * @param password 秘钥,必须为16个字符组成
     * @return 明文
     */
    public static String decrypt(String content, String password) {
        try {
            if (StringUtil.isBlank(content) || StringUtil.isBlank(password)) {
                return null;
            }

            byte[] encryptByte = Base64.getDecoder().decode(content);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(password.getBytes(), "AES"));
            byte[] decryptBytes = cipher.doFinal(encryptByte);
            return new String(decryptBytes);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * AES加密
     *
     * @param content  明文
     * @param password 秘钥,必须为16个字符组成
     * @return 密文
     */
    public static String encrypt(String content, String password) {
        try {
            if (StringUtil.isBlank(content) || StringUtil.isBlank(password)) {
                return null;
            }
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(password.getBytes(), "AES"));

            byte[] encryptStr = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptStr);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

6:创建加解密Filter类

package com.hars.user.infrastructure.filter;

import com.alibaba.fastjson.JSON;
import com.hars.common.infrastructure.utils.aes.AesUtil;
import com.hars.common.infrastructure.utils.filter.DecryptionRequestUtil;
import com.hars.common.infrastructure.utils.filter.ResponseWrapperUtil;
import com.hars.common.infrastructure.validation.security.CryptoDecryptionSecurity;
import com.hars.result.infrastructure.advice.Response;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;

/**
 * @author Huangbigao
 * @date 2020/8/28 16:26
 */
public class CryptoDecryptionFilter implements Filter {

    //方法映射集
    private List<HandlerMapping> handlerMappings;

    public CryptoDecryptionFilter(ApplicationContext applicationContext) {
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,
                HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        //判断方法上是否存在注解,如果不存在,默认加解密
        //类上的注解
        CryptoDecryptionSecurity classFlag = null;
        //方法上的注解
        CryptoDecryptionSecurity methodFlag = null;

        try {
            HandlerExecutionChain handlerExecutionChain = getHandler(httpServletRequest);
            Object handler = handlerExecutionChain != null ? handlerExecutionChain.getHandler() : null;
            if (handler instanceof HandlerMethod) {
                HandlerMethod method = (HandlerMethod) handler;
                classFlag = method.getBeanType().getAnnotation(CryptoDecryptionSecurity.class);
                methodFlag = method.getMethodAnnotation(CryptoDecryptionSecurity.class);

                //如果方法注解存在,且不加密,则直接返回
                if (methodFlag != null && !methodFlag.cryptoDecryption()) {
                    chain.doFilter(request, response);
                    return;
                }

                //如果类注解存在,且不加密,则直接返回
                if (classFlag != null && !classFlag.cryptoDecryption()) {
                    chain.doFilter(request, response);
                    return;
                }
            }
        } catch (Exception e) {
            response.setContentType("application/json; charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(Response.error("该请求无效", 601)));
            return;
        }

        CryptoDecryptionSecurity currentFlag = null;
        if (methodFlag != null) {
            currentFlag = methodFlag;
        } else if (classFlag != null) {
            currentFlag = classFlag;
        }

        //加解密密码
        String password = "Hbg584782648!@hb";
        ResponseWrapperUtil responseWrapper = null;

        //加解密处理
        if (currentFlag == null || (currentFlag.requestDecryption() && currentFlag.responseCrypto())) {
            ServletRequest requestWrapper = new DecryptionRequestUtil(httpServletRequest, password);
            responseWrapper = new ResponseWrapperUtil(httpServletResponse);
            chain.doFilter(requestWrapper, responseWrapper);
        } else if (currentFlag.requestDecryption() && !currentFlag.responseCrypto()) {
            ServletRequest requestWrapper = new DecryptionRequestUtil(httpServletRequest, password);
            chain.doFilter(requestWrapper, response);
        } else if (!currentFlag.requestDecryption() && currentFlag.responseCrypto()) {
            responseWrapper = new ResponseWrapperUtil(httpServletResponse);
            chain.doFilter(request, responseWrapper);
        } else {
            chain.doFilter(request, response);
        }

        if (responseWrapper != null) {
            byte[] content = responseWrapper.getContent();//获取返回值
            //判断是否有值
            if (content.length > 0) {
                String result = new String(content, "UTF-8");
                //加密
                String encryptStr = AesUtil.encrypt(result, password);
                //把返回值输出到客户端
                ServletOutputStream out = response.getOutputStream();
                out.write(encryptStr.getBytes());
                out.flush();
            }
        }
    }


    /**
     * 获取访问目标方法
     *
     * @param request
     * @return HandlerExecutionChain
     * @throws Exception
     */
    private HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            for (HandlerMapping hm : this.handlerMappings) {
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }
}

7:定义过滤器的拦截路径

	@Autowired
    private ApplicationContext applicationContext;
    
	/**
     * 添加加解密过滤器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean encryptionDataFilterRegistration() {
        FilterRegistrationBean<CryptoDecryptionFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CryptoDecryptionFilter(applicationContext));
        registration.addUrlPatterns("/*");
        registration.setName("cryptoDecryptionFilter");
        registration.setOrder(2);
        return registration;
    }
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐