上传文件返回403错误 - Spring MVC

Kur*_*usu 7 java spring spring-mvc spring-security

在我的Spring MVC项目中,我试图通过一个简单的表单上传文件.

HTML表格:

<form method="POST" enctype="multipart/form-data" action="/upload">
    <label>Select File</label> 
    <input type="file" name="file"/>
</form>
Run Code Online (Sandbox Code Playgroud)

我的控制器:

@Controller
public class FileController {
    @RequestMapping(value="/upload", method=RequestMethod.POST)
        public @ResponseBody String handleFileUpload(
                @RequestParam("name") String name,
                @RequestParam("file") MultipartFile file){
            if (!file.isEmpty()) {
                try {
                    //do stuff
                } catch (Exception e) {
                    return "You failed to upload " + name + " => " + e.getMessage();
                }
            } else {
                return "You failed to upload " + name + " because the file was empty.";
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

安全配置:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/upload").permitAll()
            .and()
               .exceptionHandling().accessDeniedPage("/403")
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我收到403: Forbidden错误并且每次都被重定向到我的403.html视图

到目前为止,我已经尝试MultipartFilter在单独的类中初始化Spring Security过滤器之前指定,但没有运气

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

更新:包括我的WebAppInitializer

@Configuration
@Import({ WebSecurityConfig.class })
public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println(":::Starting My App:::");
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebMVCConfig.class);
        context.setServletContext(servletContext);
        context.setConfigLocation("com.myApp.configuration");
    }

}
Run Code Online (Sandbox Code Playgroud)

我有一个servlet请求属性列表,返回以下403错误:

javax.servlet.forward.request_uri
javax.servlet.forward.context_path
javax.servlet.forward.servlet_path
__spring_security_scpf_applied
org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE
SPRING_SECURITY_403_EXCEPTION
org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER
springMacroRequestContext
themes
thymeleafEvaluationContext
org.springframework.security.web.FilterChainProxy.APPLIED
_csrf
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.FILTERED
org.springframework.security.web.csrf.CsrfFilter@539743f9.FILTERED
beans
springRequestContext
org.springframework.web.servlet.HandlerMapping.introspectTypeLevelMapping
org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER
org.springframework.web.servlet.DispatcherServlet.CONTEXT
org.springframework.core.convert.ConversionService
execInfo
org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping
org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER
org.springframework.web.servlet.resource.ResourceUrlProvider
org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP
org.springframework.web.servlet.HandlerMapping.bestMatchingPattern
org.springframework.security.web.csrf.CsrfToken
org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER
Run Code Online (Sandbox Code Playgroud)

更新#2:这肯定是CSRF问题; 当我把以下内容包含在我的内容中时我WebSecurityConfig得到了403

.csrf().disable()
Run Code Online (Sandbox Code Playgroud)

Rob*_*nch 8

这将在Spring Security参考的CSRF - Multipart(文件上载)部分中介绍.您有两种选择:

在Spring Security之前放置MultipartFilter

第一个选项是确保在Spring Security过滤器之前指定MultipartFilter.在Spring Security过滤器之前指定MultipartFilter意味着没有授权调用MultipartFilter,这意味着任何人都可以在您的服务器上放置临时文件.但是,只有授权用户才能提交由您的应用程序处理的文件.通常,这是推荐的方法,因为临时文件上载应该对大多数服务器产生可忽略的影响.

为确保在使用java配置的Spring Security过滤器之前指定MultipartFilter,用户可以覆盖beforeSpringSecurityFilterChain,如下所示:

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}
Run Code Online (Sandbox Code Playgroud)

为确保在使用XML配置的Spring Security过滤器之前指定MultipartFilter,用户可以确保将MultipartFilter的元素放在web.xml中的springSecurityFilterChain之前,如下所示:

<filter>
    <filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>MultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Run Code Online (Sandbox Code Playgroud)

包含CSRF令牌

如果允许未经授权的用户上载临时文件是不可接受的,则可以选择将MultipartFilter置于Spring Security过滤器之后,并将CSRF作为查询参数包含在表单的action属性中.jsp的示例如下所示

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" 
      method="post" 
      enctype="multipart/form-data">
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是可能泄漏查询参数.更常见的是,最好将敏感数据放入正文或标题中,以确保其不会泄露.其他信息可以在RFC 2616第15.1.3节"在URI中编码敏感信息"中找到.