若依(RuoYi)前后端分离项目实战:用Filter+Base64给所有接口穿上‘加密马甲’

张开发
2026/4/16 5:44:39 15 分钟阅读

分享文章

若依(RuoYi)前后端分离项目实战:用Filter+Base64给所有接口穿上‘加密马甲’
若依(RuoYi)前后端分离项目实战用FilterBase64实现接口数据混淆传输在开发企业内部应用或对数据安全有初步要求的项目时我们常常需要在接口传输层增加一些基础防护措施。本文将详细介绍如何在若依(RuoYi)前后端分离项目中通过Filter和Base64编码实现接口数据的简单混淆传输为API通信增加一层防君子的保护。1. 为什么选择Base64进行接口数据混淆Base64编码作为一种常见的数据编码方式虽然不能提供真正的加密安全性但在某些场景下仍然有其独特的价值简单易实现几乎所有编程语言都内置了Base64的支持无需引入复杂的加密库可读性差编码后的数据对普通人来说难以直接理解可以防止简单的数据窥探兼容性好Base64编码后的数据只包含ASCII字符可以安全地在各种系统中传输性能开销小相比真正的加密算法Base64编码解码的性能开销可以忽略不计注意Base64编码不是加密它只是将数据转换为另一种形式任何人都可以轻松解码。它适用于防君子不防小人的场景不能替代真正的加密方案如AES、RSA等。2. 前端实现改造Vue请求拦截器在若依的前端项目中我们需要对axios的请求和响应拦截器进行改造实现数据的自动编码和解码。2.1 安装并引入js-base64库首先我们需要在前端项目中引入一个可靠的Base64库npm install --save js-base64然后在项目的request.js文件中引入这个库import { Base64 } from js-base642.2 改造请求拦截器我们需要修改请求拦截器对发送的数据进行Base64编码// request.js中的请求拦截器 service.interceptors.request.use( config { // 对config.data进行Base64编码 if (config.data !(config.data instanceof FormData)) { config.data Base64.encode(JSON.stringify(config.data)) } return config }, error { return Promise.reject(error) } )2.3 改造响应拦截器同样地我们需要修改响应拦截器对接收到的数据进行Base64解码// response.js中的响应拦截器 service.interceptors.response.use( response { // 对响应数据进行Base64解码 if (response.data typeof response.data string) { try { response.data JSON.parse(Base64.decode(response.data)) } catch (e) { console.error(Base64解码失败, e) } } return response }, error { return Promise.reject(error) } )3. 后端实现编写Filter处理请求和响应在后端我们需要创建一个Filter来处理经过Base64编码的请求和响应。3.1 创建ResponseDataFilter首先创建一个实现Filter接口的类import com.ruoyi.common.utils.sign.Base64; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; public class ResponseDataFilter implements Filter { Override public void init(FilterConfig filterConfig) throws ServletException {} Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; String requestBody getRequestBody(httpRequest); // 解码请求数据 String decodedRequestBody new String(Base64.decode(requestBody), UTF-8); // 包装请求和响应 WrapperedRequest wrapRequest new WrapperedRequest(httpRequest, decodedRequestBody); WrapperedResponse wrapResponse new WrapperedResponse((HttpServletResponse) response); chain.doFilter(wrapRequest, wrapResponse); // 获取原始响应数据并编码 byte[] responseData wrapResponse.getResponseData(); String encodedResponse Base64.encode(responseData); // 写入编码后的响应 response.getOutputStream().write(encodedResponse.getBytes()); } Override public void destroy() {} private String getRequestBody(HttpServletRequest request) throws IOException { StringBuilder sb new StringBuilder(); try (BufferedReader reader request.getReader()) { String line; while ((line reader.readLine()) ! null) { sb.append(line); } } return sb.toString(); } }3.2 注册Filter为Spring Bean在Spring配置中注册我们创建的FilterConfiguration public class FilterConfig { Bean public FilterRegistrationBeanResponseDataFilter responseDataFilter() { FilterRegistrationBeanResponseDataFilter registration new FilterRegistrationBean(); registration.setFilter(new ResponseDataFilter()); registration.addUrlPatterns(/*); registration.setName(responseDataFilter); registration.setOrder(Ordered.LOWEST_PRECEDENCE); return registration; } }4. 实现请求和响应包装器为了能够修改请求和响应数据我们需要创建自定义的HttpServletRequestWrapper和HttpServletResponseWrapper。4.1 请求包装器(WrapperedRequest)import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; public class WrapperedRequest extends HttpServletRequestWrapper { private final String requestBody; public WrapperedRequest(HttpServletRequest request, String requestBody) { super(request); this.requestBody requestBody; } Override public BufferedReader getReader() throws IOException { return new BufferedReader(new StringReader(requestBody)); } Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream new ByteArrayInputStream(requestBody.getBytes(getCharacterEncoding())); return new ServletInputStream() { Override public int read() throws IOException { return byteArrayInputStream.read(); } Override public boolean isFinished() { return byteArrayInputStream.available() 0; } Override public boolean isReady() { return true; } Override public void setReadListener(ReadListener readListener) { throw new UnsupportedOperationException(); } }; } }4.2 响应包装器(WrapperedResponse)import javax.servlet.ServletOutputStream; import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.*; public class WrapperedResponse extends HttpServletResponseWrapper { private final ByteArrayOutputStream buffer; private final ServletOutputStream out; private final PrintWriter writer; public WrapperedResponse(HttpServletResponse response) throws IOException { super(response); buffer new ByteArrayOutputStream(); out new WapperedOutputStream(buffer); writer new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding())); } Override public ServletOutputStream getOutputStream() { return out; } Override public PrintWriter getWriter() { return writer; } Override public void flushBuffer() throws IOException { if (out ! null) out.flush(); if (writer ! null) writer.flush(); } public byte[] getResponseData() throws IOException { flushBuffer(); return buffer.toByteArray(); } private static class WapperedOutputStream extends ServletOutputStream { private final ByteArrayOutputStream bos; public WapperedOutputStream(ByteArrayOutputStream stream) { bos stream; } Override public void write(int b) { bos.write(b); } Override public void write(byte[] b) throws IOException { bos.write(b, 0, b.length); } Override public boolean isReady() { return true; } Override public void setWriteListener(WriteListener writeListener) { throw new UnsupportedOperationException(); } } }5. 方案适用场景与注意事项5.1 适用场景这种Base64编码的方案最适合以下场景内部系统公司内部使用的管理系统不需要高级别的安全防护临时方案在开发初期快速实现基本的数据混淆后期再替换为真正的加密性能敏感对性能要求极高不能承受加密算法的计算开销兼容性要求需要在不同系统间传输数据且这些系统可能不支持二进制数据5.2 注意事项在实际使用中需要注意以下几个问题二进制数据Base64编码会增加约33%的数据量对于大量二进制数据传输可能不适用性能影响虽然Base64本身性能开销小但对于高并发系统仍需测试实际影响安全性绝对不能将Base64编码视为加密敏感数据仍需使用真正的加密算法调试困难编码后的数据难以直接阅读会增加调试难度5.3 性能优化建议如果发现Base64编码成为性能瓶颈可以考虑以下优化措施选择性编码只对部分敏感字段进行编码而不是整个请求/响应缓存编码结果对于不经常变化的数据可以缓存编码结果并行处理对于大量数据可以使用并行流进行编码解码6. 扩展思考何时需要真正的加密虽然Base64编码在某些场景下足够使用但在以下情况下你应该考虑使用真正的加密方案传输敏感信息如用户密码、支付信息、个人隐私数据等公开网络数据需要通过互联网传输可能被中间人攻击合规要求行业或法规要求必须使用特定加密标准高价值数据保护的数据具有很高的商业或战略价值对于这些场景可以考虑使用AES对称加密或RSA非对称加密等方案它们虽然实现更复杂但能提供真正的安全保障。

更多文章