Подтвердить что ты не робот

Spring Безопасность и многостраничные запросы

У меня есть @Controller, защищенный с помощью Spring Security и OAuth2, в котором я пытаюсь разрешить моим пользователям загружать файл:

@Controller
@RequestMapping(value = "/api/image")
public class ImageController {

    @PreAuthorize("hasAuthority('ROLE_USER')")
    @RequestMapping(value = "/upload", method = RequestMethod.PUT)
    public @ResponseBody Account putImage(@RequestParam("title") String title, MultipartHttpServletRequest request, Principal principal){
        // Some type of file processing...
        System.out.println("-------------------------------------------");
        System.out.println("Test upload: " + title);
        System.out.println("Test upload: " + request.getFile("file").getOriginalFilename());
        System.out.println("-------------------------------------------");

        return ((Account) ((OAuth2Authentication) principal).getPrincipal());
    }
}

Когда я пытаюсь загрузить файл и заголовок, я получаю следующее исключение. Я устанавливаю заголовок Content-Type для multipart/form-data.

java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ [email protected]]]
    at org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver.resolveArgument(ServletRequestMethodArgumentResolver.java:84)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)

Как я могу загружать файлы за Spring Security? Похоже, что запрос никогда не превращается в MultiPartHttpServerRequest, и поэтому он не работает?

Если я изменю свою сигнатуру метода, чтобы взять файл @RequestParam MultipartFile, тогда я получаю исключение, например:

DEBUG DefaultListableBeanFactory - Returning cached instance of singleton bean 'imageController'
DEBUG ExceptionHandlerExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG ResponseStatusExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG DefaultHandlerExceptionResolver - Resolving exception from handler [public com.tinsel.server.model.Account com.tinsel.server.controller.ImageController.putImage(java.lang.String,org.springframework.web.multipart.MultipartFile,java.security.Principal)]: java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
DEBUG DispatcherServlet - Could not complete request
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
    at org.springframework.util.Assert.notNull(Assert.java:112)

... но у меня есть MultipartResolver, настроенный в моем XML:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="268435456"/> <!-- 256 megs -->
</bean>

Я видел этот пост в блоге о том, как это работает под Spring 3.0 - но я стараюсь оставаться более современным и я использую 3.1 в настоящее время. Возможно, обновленное исправление?

4b9b3361

Ответ 1

Проблема в том, что я использую PUT вместо POST. Commons FileUpload жестко закодирован, чтобы принимать только POST-запросы для файлов.

Проверьте метод isMultipartContent. Чтобы исправить это, используйте POST или расширьте этот класс и переопределите этот метод для работы, как вам нравится.

Я открыл FILEUPLOAD-214 для этой проблемы.

Ответ 2

Чтобы решить эту проблему, не используйте spring MultiPartHttpServerRequest, вместо этого отправляя запрос как HttpServletRequest, используя библиотеку загрузки apache commons для проверки запроса из метода PUT и обработки файла. Вот пример кода:

ServletFileUpload fileUpload = new ServletFileUpload(new DiskFileItemFactory());
List<FileItem> fileItems = fileUpload.parseRequest(httpServletRequest);
InputStream in = fileItems.get(0).getInputStream();
...

Ответ 3

В Config.groovy

Убедитесь, что включен параметр multipart,

// whether to disable processing of multi part requests
   grails.web.disable.multipart=false

В контроллере добавьте метод отправки

def upload(){
    MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
    if(request instanceof MultipartHttpServletRequest)
            {
                CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("myFile");
                println f.contentType
                f.transferTo()
                if(!f.empty)
                    flash.message = 'success'
                else
                    flash.message = 'file cannot be empty'
            }
    else
    flash.message = 'request is not of type MultipartHttpServletRequest'}

с этим я смог загрузить файл, ничего связанного с Spring Security.

Ответ 4

вы можете взглянуть на https://github.com/joshlong/the-spring-tutorial, в котором есть пример, демонстрирующий, как отправить сообщение в Spring MVC с помощью Spring Security OAuth включен. Я даже использую перетаскивание HTML5, чтобы перетащить изображение на экран, а затем отправить его через ajax на сервер.