Springboot如何使用filter对response内容进行加密方式
短信预约 -IT技能 免费直播动态提醒
这篇文章主要介绍Springboot如何使用filter对response内容进行加密方式,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
使用filter对response内容进行加密
编写加密类(AES)
public class AesEncryptUtils { //参数分别代表 算法名称/加密模式/数据填充方式 private static String algorithmstr = "AES/ECB/PKCS5Padding"; public static String getAlgorithmstr() { return algorithmstr; } 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); } 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类
@Componentpublic 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 } 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 } 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
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; } 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(); } 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(); } }; } 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; } @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
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())); } @Override public ServletOutputStream getOutputStream() throws IOException { return out; } @Override public PrintWriter getWriter() throws UnsupportedEncodingException { return writer; } @Override public void flushBuffer() throws IOException { if (out != null) { out.flush(); } if (writer != null) { writer.flush(); } } @Override public void reset() { buffer.reset(); } public byte[] getResponseData() throws IOException { flushBuffer(); return buffer.toByteArray(); } 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) { } }}
写配置类
@Configurationpublic class WebConfiguration { @Autowired private EncryptFilter encryptFilter; @Bean public FilterRegistrationBean registFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(encryptFilter); registration.addUrlPatterns("@Documented@Target({ElementType.METHOD, ElementType.TYPE,})@Retention(RetentionPolicy.RUNTIME)public @interface CryptoDecryptionSecurity { boolean cryptoDecryption() default true; boolean requestDecryption() default true; 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); }
创建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;public class DecryptionRequestUtil extends HttpServletRequestWrapper { private static final String APPLICATION_JSON = "application/json"; 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 class="lazy" data-src) { Map<String, String[]> map = new HashMap<>(); Map<String, String> params = JSONObject.parseObject(class="lazy" data-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; } } private class DecryptionInputStream extends ServletInputStream { private final InputStream sourceStream; 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) { } }}
创建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;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 } }}
创建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;@Slf4jpublic class AesUtil { 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; } } 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; } }
创建加解密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;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(); } } } 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; }}
定义过滤器的拦截路径
@Autowired private ApplicationContext applicationContext; @Bean public FilterRegistrationBean encryptionDataFilterRegistration() { FilterRegistrationBean<CryptoDecryptionFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new CryptoDecryptionFilter(applicationContext)); registration.addUrlPatterns("/*"); registration.setName("cryptoDecryptionFilter"); registration.setOrder(2); return registration; }
以上是“Springboot如何使用filter对response内容进行加密方式”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341