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

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

HTML表格:

我的控制器:

 @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."; } } } 

安全配置:

 @Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/upload").permitAll() .and() .exceptionHandling().accessDeniedPage("/403") } } 

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

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

 public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer { @Override protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { insertFilters(servletContext, new MultipartFilter()); } } 

有任何想法吗?

更新:包括我的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"); } } 

我有一个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 

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

 .csrf().disable() 

这将在Spring Security参考的CSRF – Multipart(文件上载)部分中介绍。 你有两个选择:

  • 在Spring Security之前放置MultipartFilter
  • 包含CSRF令牌

在Spring Security之前放置MultipartFilter

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

要确保在使用java配置的Spring Securityfilter之前指定MultipartFilter,用户可以覆盖beforeSpringSecurityFilterChain,如下所示:

 public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer { @Override protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { insertFilters(servletContext, new MultipartFilter()); } } 

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

  MultipartFilter org.springframework.web.multipart.support.MultipartFilter   springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy   MultipartFilter /*   springSecurityFilterChain /*  

包含CSRF令牌

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

 

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

我的快速解决方案如下

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %>   Upload File Request Page   
File to upload:
Name:

Press here to upload the file!

控制器代码如下:

 package com.student.controller; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.security.Principal; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; @Controller @RequestMapping("/file") public class FileUploadController { @RequestMapping(value = "", method = RequestMethod.GET) public String index(ModelMap modelMap,Principal principal,HttpServletRequest request) { return "uploadfile"; } @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) public @ResponseBody String uploadFileHandler(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { try { byte[] bytes = file.getBytes(); // Creating the directory to store file String rootPath = System.getProperty("catalina.home"); File dir = new File(rootPath + File.separator + "tmpFiles"); if (!dir.exists()) dir.mkdirs(); // Create the file on server File serverFile = new File(dir.getAbsolutePath() + File.separator + name); BufferedOutputStream stream = new BufferedOutputStream( new FileOutputStream(serverFile)); stream.write(bytes); stream.close(); return "You successfully uploaded file=" + rootPath+name; } catch (Exception e) { return "You failed to upload " + name + " => " + e.getMessage(); } } else { return "You failed to upload " + name + " because the file was empty."; } } } 

我在spring dispatcher文件中添加了以下代码