[SPRING] Spring Security로 파일 업로드 MaxUploadSizeExceededException을 멋지게 처리하는 법
SPRINGSpring Security로 파일 업로드 MaxUploadSizeExceededException을 멋지게 처리하는 법
Spring Web 4.0.5, Spring Security 3.2.4, Commons FileUpload 1.3.1, Tomcat 7을 사용하고 있습니다. 업로드 크기 제한을 초과하면 "500 Internal Server Error"라는 결과를 초래할 수 있습니다. 추한 MaxUploadSizeExceededException이 발생합니다. . 멋진 일반 팝업으로 처리하지만 오히려 제 컨트롤러가 적절한 설명 메시지로 원래 양식으로 돌아가서 처리하도록합니다.
Spring Security를 사용하지 않을 때 사용할 수있는 몇 가지 해결책을 통해 비슷한 질문을 여러 번 해 보았습니다. 내가 시험해 본 사람 중 누구도 나를 위해 일하지 않았다.
문제는 Spring Security를 사용할 때 CommonsMultipartResolver가 "multipartResolver"빈으로 추가되지 않고 "filterMultipartResolver"로 추가 될 수 있습니다.
@Bean(name="filterMultipartResolver")
CommonsMultipartResolver filterMultipartResolver() {
CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
filterMultipartResolver.setMaxUploadSize(MAXSIZE);
return filterMultipartResolver;
}
filterMultipartResolver.setResolveLazily (true)를 설정하면; 아무런 차이가 없습니다.
내 자신으로 CommonsMultipartResolver을 서브 클래스 화하고 MaxUploadSizeExceededException을 트랩하고 빈 MultipartParsingResult를 반환하는 무언가로 parseRequest () 메서드를 재정의하면 "403 Forbidden"오류가 발생합니다.
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);
}
}
}
마지막으로, 호출되지 않기 때문에 로컬 또는 글로벌 ExceptionHandler를 구현할 필요가 없습니다.
더 나은 해결책을 찾지 못한다면 업로드 크기 제한을 제거하고 컨트롤러에서 직접 처리 할 것입니다. 사용자가 파일 크기에 대한 오류 메시지를보기 전에 업로드가 끝날 때까지 기다리라는 단점이 있습니다. 저는이 모든 것을 무시할 수도 있습니다. 왜냐하면이 경우에 이미지이기 때문에 적절한 값으로 크기를 조정할 수 있기 때문입니다.
그래도이 문제에 대한 해결책을보고 싶습니다.
고맙습니다
편집하다:
스택 추적을 요청대로 추가합니다. 500이 생성되는 경우입니다.
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
해결법
-
==============================
1.추가 필터를 추가하여 예외를 catch하고 오류 페이지로 리디렉션함으로써 MaxUploadSizeExceededException을 처리 할 수 있습니다. 예를 들어, 다음과 같이 MultipartExceptionHandler 필터를 작성할 수 있습니다.
추가 필터를 추가하여 예외를 catch하고 오류 페이지로 리디렉션함으로써 MaxUploadSizeExceededException을 처리 할 수 있습니다. 예를 들어, 다음과 같이 MultipartExceptionHandler 필터를 작성할 수 있습니다.
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); } }
참고 :이 리디렉션은 양식에 대한 가정을하고 업로드합니다. 리디렉션 할 위치를 수정해야 할 수도 있습니다. 특히 GET에있는 양식의 패턴을 따르고 POST에서 처리되는 경우이 방법이 효과적입니다.
그런 다음 MultipartFilter 전에이 필터를 추가 할 수 있습니다. 예를 들어 web.xml을 사용하는 경우 다음과 같은 내용이 표시됩니다.
<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>
양식에서 HTTP 매개 변수 오류가 있는지 검사하여 오류가 발생했는지 여부를 감지 할 수 있습니다. 예를 들어, JSP에서 다음을 수행 할 수 있습니다.
<c:if test="${param.error != null}"> <p>Failed to upload...too big</p> </c:if>
추신 : 오류 처리를 논의하기 위해 문서를 업데이트하기 위해 SEC-2614를 만들었습니다.
-
==============================
2.나는 파티에 늦었다는 것을 알고 있지만 훨씬 더 우아한 해결책을 찾았다.
나는 파티에 늦었다는 것을 알고 있지만 훨씬 더 우아한 해결책을 찾았다.
멀티 파트 분석기에 대한 필터를 추가하는 대신 Controller 메소드에서 MaxUploadSizeExceededException을 추가하고 web.xml에 DelegatingFilterProxy에 대한 필터를 추가하고 요청을 리디렉션하지 않고 컨트롤러에서 예외 핸들러를 추가 할 수 있습니다.
e.f. :
방법 (컨트롤러에서) :
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST) public ResponseEntity<String> uploadFile(MultipartHttpServletRequest request) throws MaxUploadSizeExceededException { //code }
예외 처리기 (동일한 컨트롤러에서) :
@ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntity handleSizeExceededException(HttpServletRequest request, Exception ex) { //code }
Web.xml (Rob Winch에게 감사드립니다) :
<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>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> <dispatcher>ERROR</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping>
그것이 필요한 전부입니다.
-
==============================
3.문제는 다중 필터 이후에 springSecurityFilterChain을 추가해야한다는 것입니다. 그래서 당신은 403 상태를 얻고 있습니다. 이리:
문제는 다중 필터 이후에 springSecurityFilterChain을 추가해야한다는 것입니다. 그래서 당신은 403 상태를 얻고 있습니다. 이리:
http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html#csrf-multipartfilter
그 후에는 @ExceptionHandler 주석이있는 메소드가 포함 된 @ControllerAdvice 주석이있는 클래스에서 FileUploadBase.SizeLimitExceededException을 catch 할 수 있다고 생각합니다.
-
==============================
4.실험하는 동안 내놓은 해결책은 다음과 같습니다.
실험하는 동안 내놓은 해결책은 다음과 같습니다.
이렇게하면 크기가 초과 된 경우에도 양식 제출을 처리하는 데 일반적인 Controller 메서드를 사용할 수 있습니다.
이 접근법이 마음에 들지 않는 것은 외부 라이브러리 패키지 (MultipartParsingResult가 보호됨)를 엉망으로 만들고 url (덜 안전한 btw) 형식으로 토큰을 설정해야한다는 것입니다.
내가 좋아하는 것은 컨트롤러의 한 곳에서 양식 제출을 처리한다는 것입니다.
큰 파일이 사용자에게 반환되기 전에 완전히 다운로드되는 문제는 지속되지만, 이미 다른 곳에서 해결 된 것 같습니다.
from https://stackoverflow.com/questions/23856254/how-to-nicely-handle-file-upload-maxuploadsizeexceededexception-with-spring-secu by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] JSP에서 PropertyPlaceholderConfigurer에 지정된 속성 파일의 속성을 사용하는 방법 (0) | 2018.12.31 |
---|---|
[SPRING] 스프링 부트와 함께 다중 디스패처 서블릿 / 웹 컨텍스트 사용 (0) | 2018.12.31 |
[SPRING] 다중 애플리케이션 컨텍스트, 다중 디스패처 서블릿 (0) | 2018.12.31 |
[SPRING] 봄 보안. 사용자를 로그 아웃하는 방법 (oauth2 토큰 취소) (0) | 2018.12.31 |
[SPRING] Tomcat-Spring-Hibernate 웹 애플리케이션에서 'PermGen 공간 부족'예외로 수행 할 수있는 작업은 무엇입니까? (0) | 2018.12.31 |