• SpringBoot 解决HttpServletRequest只能读取一次


    业务逻辑,通过filter读取请求的request,获取token,并将token传递后面流程使用

    BodyReaderHttpServletRequestWrapper:

    public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
        private final byte[] body;
    
        public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
    
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
    
            return new ServletInputStream() {
    
                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
    
                @Override
                public boolean isFinished() {
                    return false;
                }
    
                @Override
                public boolean isReady() {
                    return false;
                }
    
                @Override
                public void setReadListener(ReadListener readListener) {
    
                }
            };
        }
    }

    RepeatReadFilter:

    /**
     * 封装HttpServletRequest为可重复读取请求
     **/
    public class RepeatReadFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            // 防止流读取一次后就没有了, 所以需要将流继续写出去
            ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
            //获取用户凭证
            String token = httpServletRequest.getHeader(Constants.USER_TOKEN);
            if(StringUtils.isBlank(token)){
                token = httpServletRequest.getParameter(Constants.USER_TOKEN);
            }
            //=================获取json格式的token字段=========================
            String body = HttpHelper.getBodyString(requestWrapper);
            if (StringUtils.isNotBlank(body)) {
                JSONObject jsonObject = JSONObject.parseObject(body);
                Object obj = jsonObject.get("token");
                if (null != obj) {
                    token = obj.toString();
                }
            }
            requestWrapper.setAttribute(Constants.USER_TOKEN,token);
            chain.doFilter(requestWrapper, response);
        }
    
        @Override
        public void destroy() {
    
        }
    }

    FilterConfig:

    @Configuration
    public class FilterConfig {
        @Bean
        public FilterRegistrationBean registFilter() {
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new RepeatReadFilter());
            registration.addUrlPatterns("/app/*");
            registration.setName("UrlFilter");
            registration.setOrder(1);
            return registration;
        }
    
    }

    AuthorizationInterceptor:

    @Component
    public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            AuthIgnore annotation;
            if(handler instanceof HandlerMethod) {
                annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthIgnore.class);
            }else{
                return true;
            }
    
            //如果有@AuthIgnore注解,则不验证token
            if(annotation != null){
                return true;
            }
    
            //获取用户凭证
            String token = request.getHeader(Constants.USER_TOKEN);
            if(StringUtils.isBlank(token)){
                token = request.getParameter(Constants.USER_TOKEN);
            }
            if(StringUtils.isBlank(token)){
                Object obj = request.getAttribute(Constants.USER_TOKEN);
                if(null!=obj){
                    token=obj.toString();
                }
            }
    
            //token凭证为空
            if(StringUtils.isBlank(token)){
                throw new AuthException(Constants.USER_TOKEN + "不能为空", HttpStatus.UNAUTHORIZED.value());
            }
    
            return true;
        }
    }

    WebMvcConfig:

    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
    
        @Autowired
        private AuthorizationInterceptor authorizationInterceptor;
    //    @Autowired
    //    private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            //argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
        }
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            super.configureMessageConverters(converters);
        }
    
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        }
    }

    在filter中读取token,在interceptor中进行读取判断使用

    HttpHelper:

    public class HttpHelper {
        /**
         * 获取请求Body
         *
         * @param request
         * @return
         */
        public static String getBodyString(ServletRequest request) {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = request.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    }

    https://blog.csdn.net/beflyabot/article/details/78053130

    https://my.oschina.net/vernon/blog/363693

  • 相关阅读:
    从Delegate.CreateDelegate看值类型的实例方法
    c#编译器如何处理匿名委托
    线程静态的几个特点
    Framework 3.5学习笔记
    看看给我用的基类,还有多少人愿意做下去
    .net里面数组的复制
    装饰模式与大接口的装饰模式的思考
    SingleTon的实现与性能
    特性与方法注入
    CLR与浮点数
  • 原文地址:https://www.cnblogs.com/hongdada/p/9171739.html
Copyright © 2020-2023  润新知