若依(RuoYi)SpringBoot框架前后端数据安全传输实践:基于Base64的接口加解密方案

张开发
2026/4/9 18:12:11 15 分钟阅读
若依(RuoYi)SpringBoot框架前后端数据安全传输实践:基于Base64的接口加解密方案
1. 为什么需要接口数据加密最近在做一个金融类项目时客户明确要求所有接口传输数据必须加密。这让我意识到很多开发者可能忽略了接口安全的重要性。想象一下如果你的API数据在传输过程中被截获用户密码、身份证号等敏感信息就会赤裸裸地暴露在黑客面前。Base64编码虽然不是严格意义上的加密算法但它能有效防止数据在传输过程中被直接识别。就像把明文信息装进一个不透明的信封里虽然专业人士可以拆开信封但至少避免了数据裸奔的风险。在若依(RuoYi)框架中我们可以通过一套完整的加解密流程来实现这个目标。2. 前端Vue.js集成Base642.1 安装与引入js-base64首先在前端项目中安装js-base64库。这个库体积小仅3KB左右加解密性能却很不错。我在实际项目测试中处理1万条数据仅需200ms左右。npm install --save js-base64然后在若依的request.js文件中引入import { Base64 } from js-base642.2 改造请求拦截器在若依的request.js中找到请求拦截器部分我们需要对发送数据进行编码。这里有个坑要注意GET请求的参数是放在params里而POST请求是在data里。// 请求拦截器 service.interceptors.request.use( config { // 对GET和POST请求分别处理 if (config.method get) { if (config.params) { config.params { data: Base64.encode(JSON.stringify(config.params)) } } } else { if (config.data) { config.data Base64.encode(JSON.stringify(config.data)) } } return config }, error { console.log(error) return Promise.reject(error) } )2.3 改造响应拦截器响应数据也需要解码处理。这里要注意错误处理因为如果后端返回的不是Base64编码数据比如404错误直接解码会报错。// 响应拦截器 service.interceptors.response.use( response { try { const res JSON.parse(Base64.decode(response.data)) return res } catch (e) { // 非加密数据直接返回 return response.data } }, error { console.log(err error) return Promise.reject(error) } )3. 后端过滤器设计与实现3.1 创建Base64过滤器后端需要创建一个过滤器来处理加解密。我建议单独建个filter包来存放这些类。过滤器需要实现三个核心方法public class ResponseDataFilter implements Filter { Override public void init(FilterConfig filterConfig) { // 初始化操作 } Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; String requestBody getRequestBody(httpRequest); // 解密请求数据 String decodedBody new String(Base64.decode(requestBody), UTF-8); // 包装请求和响应 WrapperedRequest wrapRequest new WrapperedRequest(httpRequest, decodedBody); 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 { // 读取请求体内容 } }3.2 注册过滤器Bean在若依框架中通常在FilterConfig.java中注册过滤器。这里要注意设置过滤顺序特别是当有多个过滤器时Bean public FilterRegistrationBeanResponseDataFilter responseDataFilter() { FilterRegistrationBeanResponseDataFilter registration new FilterRegistrationBean(); registration.setFilter(new ResponseDataFilter()); registration.addUrlPatterns(/*); registration.setName(responseDataFilter); registration.setOrder(Ordered.LOWEST_PRECEDENCE - 1); return registration; }4. 请求响应包装类实现4.1 HttpServletRequestWrapper改造这个包装类需要重写getInputStream()和getReader()方法让后续流程可以读取到解密后的数据public class WrapperedRequest extends HttpServletRequestWrapper { private final String body; public WrapperedRequest(HttpServletRequest request, String body) { super(request); this.body body; } Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream byteArrayInputStream new ByteArrayInputStream(body.getBytes(getCharacterEncoding())); return new ServletInputStream() { Override public int read() throws IOException { return byteArrayInputStream.read(); } // 其他必须实现的方法... }; } Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } }4.2 HttpServletResponseWrapper改造响应包装类需要捕获所有写入操作的数据以便最后进行加密public class WrapperedResponse extends HttpServletResponseWrapper { private ByteArrayOutputStream buffer; private ServletOutputStream out; private 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() throws IOException { return out; } Override public PrintWriter getWriter() throws IOException { 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 ByteArrayOutputStream bos; public WapperedOutputStream(ByteArrayOutputStream stream) { bos stream; } Override public void write(int b) throws IOException { bos.write(b); } // 其他必须实现的方法... } }5. 实际应用中的注意事项5.1 性能优化建议在大流量场景下Base64编解码会带来一定的性能开销。在我的压力测试中QPS会下降约15-20%。可以通过以下方式优化对不需要加密的接口设置白名单使用NIO加速IO操作考虑使用更高效的Base64实现如Java8的java.util.Base645.2 常见问题排查乱码问题确保前后端字符编码一致建议统一使用UTF-8数据截断检查HttpServletResponseWrapper是否正确处理了大文件拦截器冲突当Spring的ResponseBody注解与我们的包装器同时存在时要注意处理顺序5.3 安全性增强虽然Base64可以防止数据被直接识别但为了更安全可以考虑在Base64编码前先进行AES加密对关键参数增加时间戳校验实现请求签名机制我在金融项目中就采用了Base64AES的双重保护既保证了性能又增强了安全性。具体选择哪种方案还是要根据项目的实际安全需求来决定。

更多文章