【问题标题】:Consuming HttpServletRequest Multiple Times and Chain Between Methods多次使用HttpServletRequest并在方法之间链接
【发布时间】:2017-11-26 16:09:20
【问题描述】:

我必须多次阅读 HttpServletRequest。我已经像那些帖子Http Servlet request lose params from POST body after read it once中所说的那样包装了HttpServletRequest@

在我扩展 AbstractAuthenticationProcessingFilter 的过滤器类中,我可以在successfulAuthentication 方法中使用和链接请求,因为它具有链参数。但除了这些解决方案之外,我还必须在尝试和成功的身份验证步骤之间链接请求:

public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
            // wrapping request and consuming
        }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // Since i couldn't chain wrapped httpServletRequest from attemptAuthentication step, this request still gets non-wrapping one and  inputstream is empty
    }

如何将包装的请求从尝试身份验证传递到成功身份验证?

【问题讨论】:

    标签: java spring servlets


    【解决方案1】:

    这是一个老问题,但万一有人遇到同样的问题:

    您可以像上一个答案中建议的那样包装请求,但您需要在它被身份验证过滤器过滤之前包装它:

    Spring 安全配置如下所示:

    @Override
        protected void configure(HttpSecurity http) throws Exception {
            AuthFilter authFilter = new AuthFilter();
            WrapperFilter wrapperFilter = new WrapperFilter();
            http    .cors()
                    .and()
                    .csrf().disable()
                    .exceptionHandling().authenticationEntryPoint(exceptionHandler)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/v1/*", "/api/*")
                    .authenticated()
                    .and()
                    .addFilterBefore(authFilter, BasicAuthenticationFilter.class)
                    .addFilterBefore(wrapperFilter, AuthFilter.class);
        }
    

    所以包装过滤器在您的身份验证过滤器和包装过滤器的 doFilter 包装请求并将其传递之前:

    @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            MultiReadHttpServletRequest wrapper = new MultiReadHttpServletRequest((HttpServletRequest) request);
            chain.doFilter(wrapper, response);
        }
    

    而MultiReadHttpServletRequest如下:

    public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
    
        private byte[] body;
    
        public MultiReadHttpServletRequest(HttpServletRequest request) {
            super(request);
            try {
                body = IOUtils.toByteArray(request.getInputStream());
            } catch (IOException ex) {
                body = new byte[0];
            }
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return new ServletInputStream() {
                ByteArrayInputStream wrapperStream = new ByteArrayInputStream(body);
    
                @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 wrapperStream.read();
                }
            };
        }
    }
    

    【讨论】:

      【解决方案2】:

      没有这样的方法。您唯一能做的就是在每次读取请求时将其包装在一个过滤器中。只需在每次阅读复制正文之前包装请求即可。

      查看包装器的一些工作代码,例如here

      【讨论】:

      • 是的,但是包装是我可以链接包装对象的解决方案。但在这种情况下,succesfulAuthentication 无法从 atteptAuthentication 步骤获取包装的请求。如何在像链一样的尝试身份验证步骤中覆盖 HttpServletRequest?
      • @cmlonder 是否要替换当前传递给包装器实例的 HttpServletRequest 实例,并将其沿过滤器和 servlet 链的其余部分传递?
      • attemptAuthentication 步骤在 Spring 的 succesfulAuthentication 步骤之前触发。包装正在使包装的请求被多次使用。但要使用它,我必须将包装请求从尝试身份验证传递给成功身份验证。如果没有任何尝试身份验证步骤,我会在成功身份验证步骤中轻松执行此操作,方法是传递我的包装请求(如链(wrappedRequest,响应))并将其重定向到相应的 Web 服务。我只想在 attmpt 和成功的身份验证步骤之间执行此操作,但它们使用不同的请求对象。
      • @cmlonder 好的,您也想做同样的事情,但只做一次。所以答案是一样的:不幸的是,你不能
      猜你喜欢
      • 2011-12-10
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 1970-01-01
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      相关资源
      最近更新 更多