异常处理:getReader()/getInputStream() has already been called for this request
若依项目中需要在JwtAuthenticationTokenFilter的doFilterInternal方法中获取request中body中的toklen做权限验证,发现了这个问题getRead() has already been called for this request/getInputStream() has already been called for this request原
若依项目中需要在JwtAuthenticationTokenFilter的doFilterInternal方法中获取request中body中的toklen做权限验证,发现了这个问题getRead() has already been called for this request/getInputStream() has already been called for this request
原因是request.getInputStream()或request.getReader()获取到请求内容后,无法再调request.getParameter()获取请求内容。即对该类型的请求,三个方法互斥,只能调其中一个。
解决方法就是增加MyRequestWrapper类进行处理
getReader()能获取到application/json里面的参数,还有一种情况就是multipart/form-data传进来的参数,这个可以直接用request.getParameter获取。
MyRequestWrapper
package com.ruoyi.framework.security.filter;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class MyRequestWrapper extends HttpServletRequestWrapper {
private String body = null;
private String token = null;
public MyRequestWrapper(HttpServletRequest request, int type) throws IOException {
super(request);
if (type == 1) {
this.token = request.getParameter("token");
} else if (type == 2) {
this.body = RequestReadUtils.read(request);
}
}
public String getBody() {
return body;
}
public String getToken() {
return token;
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes());
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() {
return bais.read();
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public String getParameter(String name) {
return this.getToken();
}
}
RequestReadUtils
package com.ruoyi.framework.security.filter;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
public class RequestReadUtils {
private static final int BUFFER_SIZE = 1024 * 8;
public static String read(HttpServletRequest request) throws IOException {
BufferedReader bufferedReader = request.getReader();
StringWriter writer = new StringWriter();
write(bufferedReader, writer);
return writer.getBuffer().toString();
}
public static long write(Reader reader, Writer writer) throws IOException {
return write(reader, writer, BUFFER_SIZE);
}
public static long write(Reader reader, Writer writer, int bufferSize) throws IOException {
int read;
long total = 0;
char[] buf = new char[bufferSize];
while ((read = reader.read(buf)) != -1) {
writer.write(buf, 0, read);
total += read;
}
return total;
}
}
JwtAuthenticationTokenFilter
package com.ruoyi.framework.security.filter;
/**
* token过滤器 验证token有效性
*
* @author ruoyi
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private TokenService tokenService;
@Autowired
private AppService appService;
@Autowired
private ISysUserService sysUserService;
private byte[] body;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
if (request.getRequestURI().startsWith("/tabaoApi")) {
String token = null;
MyRequestWrapper requestWrapper = null;
if (request.getContentType().startsWith("multipart/form-data")) {
requestWrapper = new MyRequestWrapper(request, 1);
token = requestWrapper.getToken();
} else if (request.getContentType().startsWith("application/json")) {
requestWrapper = new MyRequestWrapper(request, 2);
token = JSONObject.parseObject(requestWrapper.getBody()).getString("token");
}
if (token != null) {
SysUser sysUser = appService.verifyAppUserToken(token);
if (sysUser != null) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser, null, null);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(requestWrapper, response);
}
}
} else {
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) {
tokenService.verifyToken(loginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
}
我这还遇到查询的列表需要分页的情况:
方法1.这个可以在doFilterInternal方法中使用request获取,然后放在requestWrapper.setAttribute(“pageNum”, request.getParameter(“pageNum”))中,在需要的地方ServletUtils.getRequestAttributes().getAttribute(“pageNum”, 0));获取。
方法2.将pageNum和pageSize放在实体类中,然后获取。
更多推荐
所有评论(0)