如何很好地处理与Spring Security MaxUploadSizeExceededException文件上传 [英] How to nicely handle file upload MaxUploadSizeExceededException with Spring Security

查看:936
本文介绍了如何很好地处理与Spring Security MaxUploadSizeExceededException文件上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是Spring Web 4.0.5,Spring Security 3.2.4,Commons FileUpload 1.3.1,Tomcat 7,当我的时候,我得到了一个丑陋的 MaxUploadSizeExceededException 上传大小限制被超过,这导致500内部服务器错误。我用一个很好的通用弹出窗口来处理它,但是我希望我的控制器可以通过返回原始窗体的正确解释信息来处理它。



I我们曾多次看到类似的问题,有些解决方案可能在不使用Spring Security的时候起作用;没有一个我尝试过为我工作。

问题可能是,当使用Spring Security时, CommonsMultipartResolver 不作为multipartResolverbean添加,而是作为filterMultipartResolver添加:

  @Bean(name =filterMultipartResolver)
CommonsMultipartResolver filterMultipartResolver(){
CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
filterMultipartResolver.setMaxUploadSize(MAXSIZE);
返回filterMultipartResolver;如果我设置 filterMultipartResolver.setResolveLazily(true);
}



如果我使用自己的子类来继承 CommonsMultipartResolver 并覆盖使用捕获 MaxUploadSizeExceededException 的东西,并返回一个空的> MultipartParsingResult code>,我得到一个403 Forbidden的错误:

pre $ public class ExtendedCommonsMultipartResolver extends CommonsMultipartResolver {
protected MultipartParsingResult parseRequest(HttpServletRequest请求)抛出MultipartException {
字符串编码= determineEncoding(请求);
试试{
return super.parseRequest(request);
} catch(MaxUploadSizeExceededException e){
return parseFileItems(Collections。< FileItem> emptyList(),encoding);





$ p $最后,实现某种本地或全局的 ExceptionHandler ,因为它永远不会被调用。



如果我找不到更好的解决方案,我只需移除上传大小限制,然后在控制器中自行处理,缺点是让用户等待直到看到有关文件大小的错误消息之前上传完成。
我甚至可以忽略所有这些,因为在这种情况下,我可以把它调整到正确的值。



不过,我我想看看这个问题的解决方案。

谢谢

编辑:



按要求添加堆栈跟踪。这是500生成的情况。

  2014年5月30日下午12时47分17秒org.apache.catalina。 core.StandardWrapperValve调用
SEVERE:Servlet.service()用于上下文路径[/ site]中的servlet [dispatcher]抛出异常
org.springframework.web.multipart.MaxUploadSizeExceededException:最大上传大小为1000000字节超标;嵌套的异常是org.apache.commons.fileupload.FileUploadBase $ SizeLimitExceededException:该请求被拒绝,因为它的大小(3403852)超过了org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest中配置的最大值(1000000)
(CommonsMultipartResolver.java:162)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:142)
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal (MultipartFilter.java:110)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java :243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
在org.apache.catalina .core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve .invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve .java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:409 )
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1044)
at org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process(AbstractProtocol.java:607)
在org.apache.tomcat.util.net.JIoEndpoint $ SocketProcessor.run(JIoEndpoint.java:315)
在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.ja va:1110)
在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:603)$ b $在java.lang.Thread.run(Thread.java:722)
由于:org.apache.commons.fileupload.FileUploadBase $ SizeLimitExceededException:该请求被拒绝,因为它的大小(3403852)超过了配置的最大值(1000000)
在org.apache.commons.fileupload.FileUploadBase $ FileItemIteratorImpl。< ;(init)>(FileUploadBase.java:965)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest((FileUploadBase.java:334) CommonsMultipartResolver.java:158)
... 19 more


解决方案

您可以处理MaxUploadSizeE xceededException通过添加一个额外的Filter来捕获异常并重定向到一个错误页面。例如,您可以创建一个MultipartExceptionHandler过滤器,如下所示:

pre $ public $ MultipartExceptionHandler extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest请求,
HttpServletResponse响应,FilterChain filterChain)
抛出ServletException,IOException {
try {
filterChain.doFilter(request,response );
catch(MaxUploadSizeExceededException e){
handle(request,response,e);
} catch(ServletException e){
if(e.getRootCause()instanceof MaxUploadSizeExceededException){
handle(request,response,(MaxUploadSizeExceededException)e.getRootCause());
} else {
throw e;



$ b private void handle(HttpServletRequest request,
HttpServletResponse response,MaxUploadSizeExceededException e)throws ServletException,IOException {

String redirect = UrlUtils.buildFullRequestUrl(request)+?error;
response.sendRedirect(重定向);
}

}

注意:这个重定向对你的表单和上传做了一个假设。您可能需要修改重定向到的位置。特别是如果你按照你的表单模式在GET,并在POST处理,这将工作。

然后,您可以确保在MultipartFilter之前添加此过滤器。例如,如果您使用的是web.xml,您会看到如下所示:

 < filter> 
< filter-name> meh< / filter-name>
< filter-class> org.example.web.MultipartExceptionHandler< / filter-class>
< / filter>
< filter>
< description>
允许应用程序接受多部分文件数据。
< / description>
< display-name> springMultipartFilter< / display-name>
< filter-name> springMultipartFilter< / filter-name>
< filter-class> org.springframework.web.multipart.support.MultipartFilter< / filter-class>
<! - init-param>
< param-name> multipartResolverBeanName< / param-name>
< param-value> multipartResolver< / param-value>
< / init-param - >
< / filter>
< filter>
< description>
使用Spring Security框架保证对Web资源的访问。
< / description>
< display-name> springSecurityFilterChain< / display-name>
< filter-name> springSecurityFilterChain< / filter-name>
< filter-class> org.springframework.web.filter.DelegatingFilterProxy< / filter-class>
< / filter>

< filter-mapping>
< filter-name> meh< / filter-name>
< url-pattern> / *< / url-pattern>
< / filter-mapping>
< filter-mapping>
< filter-name> springMultipartFilter< / filter-name>
< url-pattern> / *< / url-pattern>
< / filter-mapping>
< filter-mapping>
< filter-name> springSecurityFilterChain< / filter-name>
< url-pattern> / *< / url-pattern>
< dispatcher> ERROR< / dispatcher>
< dispatcher>请求< /调度器>
< / filter-mapping>

在表单中,您可以通过检查是否存在HTTP参数错误来检测错误是否发生。例如,在JSP中,您可以执行以下操作:

 < c:if test =$ {param.error! = null}> 
< p>无法上传...太大< / p>
< / c:if>

PS:我创建了 SEC-2614 来更新文档来讨论错误处理

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 size limit is exceeded, which results in a "500 Internal Server Error". I handle it with a nice generic popup, but I'd rather have my Controller take care of it by going back to the originating form with the proper explanation message.

I've seen a similar question asked many times, with a few solutions that might work when not using Spring Security; none of the ones I tried worked for me.

The problem might be that when using Spring Security, the CommonsMultipartResolver is not added as a "multipartResolver" bean but as a "filterMultipartResolver":

@Bean(name="filterMultipartResolver")
CommonsMultipartResolver filterMultipartResolver() {
    CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
    filterMultipartResolver.setMaxUploadSize(MAXSIZE);
    return filterMultipartResolver;
}

If I set filterMultipartResolver.setResolveLazily(true); it makes no difference.

If I subclass the CommonsMultipartResolver with my own and override the parseRequest() method with something that traps the MaxUploadSizeExceededException and returns an empty MultipartParsingResult, I get a "403 Forbidden" error:

public class ExtendedCommonsMultipartResolver extends CommonsMultipartResolver {
    protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
        String encoding = determineEncoding(request);
        try {
            return super.parseRequest(request);
        } catch (MaxUploadSizeExceededException e) {
            return parseFileItems(Collections.<FileItem> emptyList(), encoding);
        }
    }
}

Finally, there's no point in implementing some kind of local or global ExceptionHandler because it is never called.

If I don't find a better solution, I'll just remove the upload size limit and handle it myself in the controller, with the drawback of having the user wait until the upload is finished before seeing the error message about file size. Of I might even ignore all of this because, being it an image in this case, I could just resize it down to proper values.

Still, I'd like to see a solution to this problem.

Thank you

EDIT:

I add the stack trace as requested. This is the case where a 500 is generated.

May 30, 2014 12:47:17 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/site] threw exception
org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size of 1000000 bytes exceeded; nested exception is org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (3403852) exceeds the configured maximum (1000000)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:162)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:142)
    at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:110)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:409)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1044)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
Caused by: org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (3403852) exceeds the configured maximum (1000000)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
    at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
    at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:334)
    at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:158)
    ... 19 more

解决方案

You can handle the MaxUploadSizeExceededException by adding an additional Filter to catch the exception and the redirect to an error page. For example, you could create a MultipartExceptionHandler Filter like the following:

public class MultipartExceptionHandler extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } catch (MaxUploadSizeExceededException e) {
            handle(request, response, e);
        } catch (ServletException e) {
            if(e.getRootCause() instanceof MaxUploadSizeExceededException) {
                handle(request, response, (MaxUploadSizeExceededException) e.getRootCause());
            } else {
                throw e;
            }
        }
    }

    private void handle(HttpServletRequest request,
            HttpServletResponse response, MaxUploadSizeExceededException e) throws ServletException, IOException {

        String redirect = UrlUtils.buildFullRequestUrl(request) + "?error";
        response.sendRedirect(redirect);
    }

}

NOTE: This redirect makes an assumption about your form and upload. You may need to modify where to redirect to. Specifically if you follow the pattern of your form being at GET and it is processed at POST this will work.

You can then ensure to add this Filter before MultipartFilter. For example, if you are using web.xml you would see something like this:

<filter>
    <filter-name>meh</filter-name>
    <filter-class>org.example.web.MultipartExceptionHandler</filter-class>
</filter>
<filter>
    <description>
        Allows the application to accept multipart file data.
    </description>
    <display-name>springMultipartFilter</display-name>
    <filter-name>springMultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    <!--init-param>
        <param-name>multipartResolverBeanName</param-name>
        <param-value>multipartResolver</param-value>
    </init-param-->
</filter>
<filter>
    <description>
        Secures access to web resources using the Spring Security framework.
    </description>
    <display-name>springSecurityFilterChain</display-name>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>meh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>springMultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>ERROR</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

In your form you can then detect if the error occurred by inspecting if the HTTP parameter error is present. For example, in a JSP you might do the following:

<c:if test="${param.error != null}">
    <p>Failed to upload...too big</p>
</c:if>

PS: I created SEC-2614 to update the documentation to discuss error handling

这篇关于如何很好地处理与Spring Security MaxUploadSizeExceededException文件上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆