【Java】RuoYi+SpringBoot+前后端分离版添加接口加密(参考)
这次更新参考了其他博主内容,在基础上做了备注及调整。
·
这次更新参考了其他博主内容,在基础上做了备注及调整
1. 前端加解密
1.1 下载开源的base64
npm install --save js-base64
1.2 在request.js引入base64
request.js地址在ruoyi-ui/src/utils/request.js
引入代码
import {Base64} from 'js-base64'
1.3 在request.js中的request拦截器-对config.data进行加密处理
// base64加密请求数据
config.data = Base64.encode(typeof config.data === 'object' ? JSON.stringify(config.data) : config.data)
1.4 在request.js中的response响应器-对接收的数据进行解密处理
//判断后端接口给的数据是否加密
let res;
if(resjm.data.code == null){
// base64解密
const resjmh = Base64.decode(resjm.data)
res = {};
res.data = JSON.parse(resjmh);
}else{
res = resjm;
}
// 二进制数据则直接返回
if (resjm.request.responseType === 'blob' || resjm.request.responseType === 'arraybuffer') {
return resjm.data
}
这里和教程内容存在不一样的地方,是直接解密会出现后端有些接口没做加密处理,还有一些异常抛出也没做加密,如果直接解密会报错,需要过滤掉这类数据部解密。
2. 后端加解密
2.1 新增过滤器ResponseDataFilter(名字随意,在注册Bean的时候一致就行)
我这边统一放在了com.ruoyi.common.utils.Base64Decrypt下面
import com.ruoyi.common.utils.sign.Base64;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
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 {
String uri = ((HttpServletRequest) request).getRequestURI();
// 如果是非 multipart/form-data 类型(文件)的请求,则进行解密处理,否则不处理
if ("/common/upload".equals(uri)) {
chain.doFilter(request, response);
} else {
HttpServletRequest requests = (HttpServletRequest) request;
String requestBody = getRequestBody(requests);
//解密请求报文
String requestBodyMw = new String(Base64.decode(requestBody), "utf-8");
WrapperedRequest wrapRequest = new WrapperedRequest( (HttpServletRequest) request, requestBodyMw);
WrapperedResponse wrapResponse = new WrapperedResponse((HttpServletResponse) response);
chain.doFilter(wrapRequest, wrapResponse);
byte[] data = wrapResponse.getResponseData();
// 加密返回报文.如果是/tool/gen/batchGenCode,代码下载接口,则不加密
if(!"/tool/gen/batchGenCode".equals(uri)){
String responseBodyMw = Base64.encode(data);
response.getOutputStream().write(responseBodyMw.getBytes());
}else {
response.getOutputStream().write(data);
}
}
}
@Override
public void destroy() {
// 销毁操作,可留空
}
private String getRequestBody(HttpServletRequest req) {
try {
BufferedReader reader = req.getReader();
StringBuffer sb = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
return json;
} catch (IOException e) {
System.out.println("请求体读取失败"+e.getMessage());
}
return "";
}
}
这里有多做了两个判断,第一个/common/upload是文件上传的类型,如果走常规加密,这边会报错,也可以根据HTTP请求的Content-Type设置为multipart/form-data,然后排除整个类型,第二个/tool/gen/batchGenCode是自动生成文件打包下载的地址,也排除掉加密。
2.2 把自己添加过滤器注册为bean(在FilterConfig.java文件写,也可以自己写配置文件)
我这边在com.ruoyi.framework.config.FilterConfig添加
@Bean
public FilterRegistrationBean requestDataFilter()
{
FilterRegistrationBean registration = new FilterRegistrationBean();
//自己的过滤器叫什么名字就写上什么名字
registration.setFilter(new ResponseDataFilter());
registration.addUrlPatterns("/*");
registration.setName("responseDataFilter");
//过滤器的顺序,数字越小,越先执行,反之亦然
registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
return registration;
}
2.3 继承HttpServletRequestWrapper和继承HttpServletResponseWrapper
我这边统一放在了com.ruoyi.common.utils.Base64Decrypt下面
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class WrapperedResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer = null;
private ServletOutputStream out = null;
private PrintWriter writer = null;
public WrapperedResponse(HttpServletResponse resp) throws IOException {
super(resp);
// 真正存储数据的流
buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer,
this.getCharacterEncoding()));
}
/** 重载父类获取outputstream的方法 */
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
}
/** 重载父类获取writer的方法 */
@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
return writer;
}
/** 重载父类获取flushBuffer的方法 */
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
}
@Override
public void reset() {
buffer.reset();
}
/** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();
}
/** 内部类,对ServletOutputStream进行包装 */
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() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
// TODO Auto-generated method stub
}
}
}
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class WrapperedRequest extends HttpServletRequestWrapper {
private String requestBody = null;
HttpServletRequest req = null;
public WrapperedRequest(HttpServletRequest request) {
super(request);
this.req = request;
}
public WrapperedRequest(HttpServletRequest request, String requestBody) {
super(request);
this.requestBody = requestBody;
this.req = request;
}
/**
* (non-Javadoc)
*
* @see javax.servlet.ServletRequestWrapper#getReader()
*/
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new StringReader(requestBody));
}
/**
* (non-Javadoc)
*
* @see javax.servlet.ServletRequestWrapper#getInputStream()
*/
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
private InputStream in = new ByteArrayInputStream(
requestBody.getBytes(req.getCharacterEncoding()));
@Override
public int read() throws IOException {
return in.read();
}
@Override
public boolean isFinished() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
// TODO Auto-generated method stub
}
};
}
}
大佬的资料让我是受益匪浅,本文仅在大佬的基础上结合我实际的项目进行一些更细的文字说明
参考链接:https://blog.csdn.net/Haoxiansheng1/article/details/133939598
————————————————
本文还存在文件上传下载问题,并未加入到代码中,主要是方式是添加过滤
更多推荐
已为社区贡献1条内容
所有评论(0)