问题产生原因:
ServletRequest, ServletResponse 采用的是输入流的方式,所以只能读取一次。在使用filter拦截取值之后,后续不能再次调用
问题解决方法:使用自定义bean将数据保存到bean中,实现可以重复调用
自定义标签代码:
/**
* @description: 判断是否需要校验token和sig
* @author: hyx
* @create: 2021-08-23 14:50
**/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginTokenAndSig {
/**
* 是否校验token合法性 默认 是
*
* @return
*/
boolean tokenValidate() default true;
/**
* 是否校验签名合法性 默认 是
*
* @return
*/
boolean signValidate() default true;
}
Filter拦截代码
注:自定义 response需要在chain.doFilter执行之后才能获取到返回值。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sy.debug.base.Response;
import com.sy.debug.base.untils.SeqUtil;
import com.sy.debug.http.aes.HMacMD5;
import com.sy.debug.http.auth.RequestBodyContent;
import com.sy.debug.http.auth.wrapper.MyRequestWrapper;
import com.sy.debug.http.auth.wrapper.MyResponseWrapper;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class HttpServletRequestReplacedFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MyRequestWrapper requestWrapper = null;
MyResponseWrapper responseWrapper = null;
if (request instanceof HttpServletRequest) {
requestWrapper = new MyRequestWrapper((HttpServletRequest) request);
}
if (response instanceof HttpServletResponse) {
responseWrapper = new MyResponseWrapper((HttpServletResponse) response);
}
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
// 在chain.doFiler方法中传递新的request对象
if (requestWrapper == null) {
if (responseWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(request, responseWrapper);
}
} else {
if (responseWrapper == null) {
chain.doFilter(requestWrapper, response);
} else {
chain.doFilter(requestWrapper, responseWrapper);
}
}
String action = null;
String json = responseWrapper.getString();
if (json != null && json.length() > 0) {
try {
JSONObject jsonObject = JSON.parseObject(json);
action = jsonObject.getString("data");
} catch (Exception e) {
action = json;
}
}
HttpServletResponse servletResponse = (HttpServletResponse) response;
HttpServletRequest servletRequest = (HttpServletRequest) request;
Response myResponse = new Response();
try {
JSONObject jsonObject = JSON.parseObject(action);
myResponse.setData(jsonObject);
}catch (Exception e){
myResponse.setData(action);
}
String operatorID = servletRequest.getHeader("OperatorID");
Long timeStamp = System.currentTimeMillis();
String seq = SeqUtil.getUniqueInstance().getSeq(timeStamp);
//自行添加返回值参数
myResponse.setOperatorID(operatorID);
myResponse.setTimeStamp(timeStamp);
myResponse.setSeq(seq);
myResponse.setSig(sig);
servletResponse.getOutputStream().write(JSON.toJSONString(myResponse).getBytes());
servletResponse.getOutputStream().flush();
}
@Override
public void destroy() {
}
}
校验代码
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
// 从 http 请求头中取出 token
String token = httpServletRequest.getHeader("Authorization");
MyRequestWrapper requestWrapper = new MyRequestWrapper((HttpServletRequest) httpServletRequest);
if (object instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(UserLoginTokenAndSig.class)) {
JSONObject jsonObject = JSON.parseObject(requestWrapper.getBody());
String operatorID = jsonObject.getString("operatorID");
UserLoginTokenAndSig userLoginToken = method.getAnnotation(UserLoginTokenAndSig.class);
if (userLoginToken.tokenValidate()) {
// 执行认证
if (token == null) {
log.info("无效token:{}", token);
httpServletResponse.getOutputStream().write("无效token,请重新登录".getBytes());
httpServletResponse.getOutputStream().flush();
return false;
}
//获取用户,用于校验用户账号是否存在
// OperatorSecret operatorSecret =
// if (operatorSecret == null) {
// log.info("用户不存在:operatorID:{}", operatorID);
// httpServletResponse.getOutputStream().write("用户不存在".getBytes());
// httpServletResponse.getOutputStream().flush();
// return false;
// }
// 验证 token
//
Boolean isVerify = JWTUtil.verifyToken(token, operatorSecret.getOperatorSecret());
if (!isVerify) {
log.info("token已失效:token:{}", token);
httpServletResponse.getOutputStream().write("token已失效".getBytes());
httpServletResponse.getOutputStream().flush();
return false;
}
}
//签名验证
if (userLoginToken.signValidate()) {
String sig = jsonObject.getString("sig");
String timeStamp = jsonObject.getString("timeStamp");
String seq = jsonObject.getString("seq");
//自定义生产签名方法
// valueSig = ***;
//自定义生产签名方法
if (!(valueSig != null && valueSig.equals(sig))) {
log.info("签名校验错误sig:{},valueSig:{}", sig, valueSig);
httpServletResponse.getOutputStream().write("签名校验错误".getBytes());
httpServletResponse.getOutputStream().flush();
return false;
} else {
log.info("签名校验成功sig:{},valueSig:{}", sig, valueSig);
}
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object o, ModelAndView modelAndView) throws IOException {
}
}
自定义request
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = 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 byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
自定义response
public class MyResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
private PrintWriter pwrite;
public MyResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MyServletOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(bytes);
}
public String getString(){
return new String(getBytes());
}
/**
*
* 获取响应数据
* @param
* @return byte[]
* @throws
* @author pf
* @datetime 2016年4月28日 下午4:23:33
*/
public byte[] getBytes() {
if(null != pwrite) {
pwrite.close();
return bytes.toByteArray();
}
if(null != bytes) {
try {
bytes.flush();
} catch(IOException e) {
e.printStackTrace();
}
}
return bytes.toByteArray();
}
private class MyServletOutputStream extends ServletOutputStream {
@Override
public void write(int b) throws IOException {
bytes.write(b); // 将数据写到 stream 中
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
}
}