How to nicely handle file upload MaxUploadSizeExceededException with Spring Security

前端 未结 4 1737
梦如初夏
梦如初夏 2020-12-05 05:20

I\'m using Spring Web 4.0.5, Spring Security 3.2.4, Commons FileUpload 1.3.1, Tomcat 7 and I\'m getting an ugly MaxUploadSizeExceededException when my upload si

4条回答
  •  再見小時候
    2020-12-05 05:50

    The solution I came up with while experimenting is the following:

    1. Extend CommonsMultipartResolver in order to swallow the exception. I add the exception to the Request just in case you want to use it in the Controller, but I don't think it's needed

      package org.springframework.web.multipart.commons;
      
      import java.util.Collections;
      
      import javax.servlet.http.HttpServletRequest;
      
      import org.apache.commons.fileupload.FileItem;
      import org.springframework.web.multipart.MaxUploadSizeExceededException;
      import org.springframework.web.multipart.MultipartException;
      
      public class ExtendedCommonsMultipartResolver extends CommonsMultipartResolver {
          @Override
          protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
              try {
                  return super.parseRequest(request);
              } catch (MaxUploadSizeExceededException e) {
                  request.setAttribute("MaxUploadSizeExceededException", e);
                  return parseFileItems(Collections. emptyList(), null);
              }
          }
      }
      
    2. Declare your resolver in the WebSecurityConfigurerAdapter, in place of CommonsMultipartResolver (you should declare a filterMultipartResolver in any case so nothing new here)

      @Bean(name="filterMultipartResolver")
      CommonsMultipartResolver filterMultipartResolver() {
          CommonsMultipartResolver filterMultipartResolver = new ExtendedCommonsMultipartResolver();
          filterMultipartResolver.setMaxUploadSize(MAXBYTES);
          return filterMultipartResolver;
      }
      
    3. Remember to define the correct filter precedence in the AbstractSecurityWebApplicationInitializer as stated in the docs (you'd do this in any case)

      @Order(1)
      public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
          @Override
          protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
              insertFilters(servletContext, new MultipartFilter());
          }
      }
      
    4. Add the _csrf token to the form action URL (I'm using thymeleaf here)

    5. In the Controller, just check for null on the MultipartFile, something like (snippet not checked for errors):

      @RequestMapping(value = "/submitImage", method = RequestMethod.POST)
      public String submitImage(MyFormBean myFormBean, BindingResult bindingResult, HttpServletRequest request, Model model) {
          MultipartFile multipartFile = myFormBean.getImage();
          if (multipartFile==null) {
              bindingResult.rejectValue("image", "validation.image.filesize");
          } else if (multipartFile.isEmpty()) {
              bindingResult.rejectValue("image", "validation.image.missing");
      

    This way you can use the usual Controller method for handling the form submission even in case of size exceeded.

    What I don't like of this approach is that you have to mess with an external library package (MultipartParsingResult is protected) and that you have to remember setting the token on the form url (which is also less secure btw).

    What I do like is that you handle the form submission in just one place in the controller.

    The problem of a big file being fully downloaded before returning to the user also persists, but I guess it is addressed somewhere else already.

提交回复
热议问题