当前位置:   article > 正文

解决HttpServletRequest的输入流只能读取一次的问题,request可重复读_xss校验拦截 request 重复读问题

xss校验拦截 request 重复读问题

原文连接:http://www.360doc.com/document/19/0106/20/39911641_807065847.shtml

原文连接中有对 可重复读 和 验签业务逻辑的大致说明

代码实现步骤

第一步

编写 RequestWrapper类  extends HttpServletRequestWrapper
  1. package com.xihongshi.common.filter;
  2. import lombok.extern.slf4j.Slf4j;
  3. import javax.servlet.ReadListener;
  4. import javax.servlet.ServletInputStream;
  5. import javax.servlet.ServletRequest;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletRequestWrapper;
  8. import java.io.*;
  9. import java.nio.charset.Charset;
  10. /**
  11. * @author mgq
  12. * @since 2021-03-30 9:59
  13. */
  14. @Slf4j
  15. public class RequestWrapper extends HttpServletRequestWrapper {
  16. /**
  17. * 存储body数据
  18. */
  19. private final byte[] body;
  20. public RequestWrapper(final HttpServletRequest request) {
  21. super(request);
  22. // 将body数据存储起来
  23. String bodyStr=getBodyString(request);
  24. // 初始化body
  25. body = bodyStr.getBytes(Charset.defaultCharset());
  26. }
  27. public String getBodyString(ServletRequest request) {
  28. try {
  29. return inputStream2String(request.getInputStream());
  30. } catch (IOException e) {
  31. log.error("",e);
  32. throw new RuntimeException(e);
  33. }
  34. }
  35. public String getBodyString() {
  36. final InputStream byteArrayInputStream = new ByteArrayInputStream(body);
  37. return inputStream2String(byteArrayInputStream);
  38. }
  39. private String inputStream2String(InputStream inputStream) {
  40. StringBuilder sb = new StringBuilder();
  41. BufferedReader reder = null;
  42. try {
  43. reder=new BufferedReader(new InputStreamReader(inputStream,Charset.defaultCharset()));
  44. String line;
  45. while ((line=reder.readLine())!=null){
  46. sb.append(line);
  47. }
  48. } catch (Exception e) {
  49. log.error("",e);
  50. throw new RuntimeException(e);
  51. }finally {
  52. if (reder!=null) {
  53. try {
  54. reder.close();
  55. } catch (IOException e) {
  56. log.error("",e);
  57. }
  58. }
  59. }
  60. return sb.toString();
  61. }
  62. @Override
  63. public BufferedReader getReader() throws IOException {
  64. return new BufferedReader(new InputStreamReader(getInputStream()));
  65. }
  66. @Override
  67. public ServletInputStream getInputStream() throws IOException {
  68. final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
  69. return new ServletInputStream() {
  70. @Override
  71. public boolean isFinished() {
  72. return false;
  73. }
  74. @Override
  75. public boolean isReady() {
  76. return false;
  77. }
  78. @Override
  79. public void setReadListener(final ReadListener readListener) {
  80. }
  81. @Override
  82. public int read() throws IOException {
  83. return inputStream.read();
  84. }
  85. };
  86. }
  87. }

 第二步

编写 ReplaceStreamFilter类,implements Filter

 

  1. package com.xihongshi.common.filter;
  2. import lombok.extern.slf4j.Slf4j;
  3. import javax.servlet.*;
  4. import javax.servlet.FilterConfig;
  5. import javax.servlet.http.HttpServletRequest;
  6. import java.io.IOException;
  7. /**
  8. * @author mgq
  9. * @since 2021-03-30 10:20
  10. */
  11. @Slf4j
  12. public class ReplaceStreamFilter implements Filter {
  13. @Override
  14. public void init(FilterConfig filterConfig) throws ServletException {
  15. log.info("StreamFilter初始化");
  16. }
  17. @Override
  18. public void doFilter(final ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  19. ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
  20. chain.doFilter(requestWrapper,response);
  21. }
  22. @Override
  23. public void destroy() {
  24. log.info("StreamFilter销毁");
  25. }
  26. }

 第三步

编写JWTInterceptor类,implements HandlerInterceptor  用于测试从request的body中取数据,验证后续接口是否能接收到@requestBody中的数据

 

  1. package com.xihongshi.client.interceptor;
  2. import com.auth0.jwt.JWT;
  3. import com.xihongshi.common.constants.RedisConstants;
  4. import com.xihongshi.common.errcode.BizErrorCodeEnum;
  5. import com.xihongshi.common.exception.BizException;
  6. import com.xihongshi.common.exception.InvalidSessionException;
  7. import com.xihongshi.common.filter.RepeatableRequestWrapper;
  8. import com.xihongshi.common.filter.RequestWrapper;
  9. import com.xihongshi.utils.JwtUtils;
  10. import com.xihongshi.utils.RedisUtil;
  11. import lombok.extern.slf4j.Slf4j;
  12. import me.chanjar.weixin.common.util.SignUtils;
  13. import org.slf4j.MDC;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.beans.factory.annotation.Value;
  16. import org.springframework.web.servlet.HandlerInterceptor;
  17. import org.springframework.web.servlet.ModelAndView;
  18. import javax.servlet.ServletInputStream;
  19. import javax.servlet.http.HttpServletRequest;
  20. import javax.servlet.http.HttpServletResponse;
  21. import java.io.BufferedReader;
  22. import java.io.InputStream;
  23. /**
  24. *
  25. * @author: mengshaoshuai
  26. * @date 2021年3月12日 下午1:51:20
  27. */
  28. @Slf4j
  29. public class JWTInterceptor implements HandlerInterceptor {
  30. @Value("${client.auth.test.enabled:false}")
  31. private boolean authTestEnabled = false;
  32. @Value("${client.auth.test.accountId:}")
  33. private Integer authTestAccountId;
  34. @Autowired
  35. JwtUtils jwtUtils;
  36. @Autowired
  37. RedisUtil redisUtil;
  38. @Override
  39. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  40. throws Exception {
  41. String token = request.getHeader("token");
  42. String sb = new RequestWrapper(request).getBodyString();
  43. System.out.println(sb);
  44. try {
  45. jwtUtils.verify(token);
  46. } catch (Exception e) {
  47. if(authTestEnabled) {
  48. //test
  49. request.setAttribute("unionId", authTestAccountId+"");
  50. request.setAttribute("accountId", authTestAccountId+"");
  51. }else{
  52. throw new InvalidSessionException(BizErrorCodeEnum.JWT_TOKEN_ERROR);
  53. }
  54. return true;
  55. }
  56. String id = JWT.decode(token).getAudience().get(0);
  57. String tknow = (String)redisUtil.get(RedisConstants.JWT_KEY_ACCOUNT+id);
  58. if(tknow==null || !tknow.equals(token)) {
  59. throw new BizException(BizErrorCodeEnum.JWT_TOKEN_EXPIRE);
  60. }
  61. String mobile = JWT.decode(token).getClaim("mobile").asString();
  62. request.setAttribute("accountId", id);
  63. request.setAttribute("unionId", mobile);
  64. return true;
  65. }
  66. @Override
  67. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  68. clearMdc();
  69. }
  70. @Override
  71. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  72. clearMdc();
  73. }
  74. /**
  75. * 清理日志上下文
  76. */
  77. protected void clearMdc() {
  78. try {
  79. MDC.clear();
  80. } catch (Exception e) {
  81. e.printStackTrace();
  82. }
  83. }
  84. }

第四步

过滤配置类  
注意:第四不和第五步必须配置,要不然1和2步骤不生效
  1. package com.xihongshi.client.interceptor;
  2. import com.xihongshi.common.filter.RepeatableReadFilter;
  3. //import com.xihongshi.common.filter.ReplaceStreamFilter;
  4. import com.xihongshi.common.filter.ReplaceStreamFilter;
  5. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import javax.servlet.Filter;
  9. /**
  10. * 过滤配置类
  11. * @author mgq
  12. * @since 2021-03-30 10:52
  13. */
  14. @Configuration
  15. public class FilterConfig {
  16. /**
  17. * 注册过滤器
  18. * @return
  19. */
  20. @Bean
  21. public FilterRegistrationBean someFilterRegistration(){
  22. FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
  23. filterRegistrationBean.setFilter(replaceStreamFilter());
  24. filterRegistrationBean.addUrlPatterns("/*");
  25. filterRegistrationBean.setName("streamFilter");
  26. return filterRegistrationBean;
  27. }
  28. /**
  29. * 实例化StreamFilter
  30. * @return
  31. */
  32. @Bean(name="replaceStreamFilter")
  33. public Filter replaceStreamFilter(){
  34. return new ReplaceStreamFilter();
  35. }
  36. }

第五步

拦截器配置
  1. package com.xihongshi.client.interceptor;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.web.servlet.HandlerInterceptor;
  6. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  7. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  8. /**
  9. * 拦截器配置
  10. * @author mgq
  11. * @since 2021-03-30 11:12
  12. */
  13. @Slf4j
  14. @Configuration
  15. public class InterceptorConfig implements WebMvcConfigurer {
  16. @Bean
  17. public JWTInterceptor getJWTInterceptor(){
  18. return new JWTInterceptor();
  19. }
  20. @Override
  21. public void addInterceptors(InterceptorRegistry registry) {
  22. registry.addInterceptor(getJWTInterceptor())
  23. .addPathPatterns("/**");
  24. }
  25. }

 第六步

随便写一个controller接口,在接口中调用参数是@requestbody 接收的json对象

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/550866
推荐阅读
相关标签
  

闽ICP备14008679号