ti-enxame.com

Solicitações Spring Security & Multipart

Eu tenho um @Controller protegido com Spring Security e OAuth2 no qual estou tentando permitir que meus usuários enviem um arquivo:

@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());
    }
}

Quando tento fazer upload de um arquivo e um título, recebo a seguinte exceção. Estou definindo o cabeçalho Content-Type como 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)

Como posso fazer upload de arquivos por trás do Spring Security? Parece que a solicitação nunca é transformada em um MultiPartHttpServerRequest e, portanto, não funciona?

Se eu alterar minha assinatura de método para obter um @RequestParam MultipartFile, recebo uma exceção como:

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)

... mas eu tenho um MultipartResolver configurado no meu XML:

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

Eu vi este post no blog sobre como fazer isso funcionar no Spring 3. - mas estou tentando me manter mais atualizado e usando o 3.1 atualmente. Existe talvez uma correção atualizada?

23
Matthew Runo

O problema é que estou usando um PUT em vez de um POST. O FileUpload do Commons é codificado para aceitar apenas pedidos de arquivos POST).

Verifique o método isMultipartContent lá. Para corrigir isso, use um POST ou estenda essa classe e substitua esse método para funcionar como quiser).

Abri FILEUPLOAD-214 para este problema.

25
Matthew Runo

Para resolver o problema, não use o Spring MultiPartHttpServerRequest, em vez disso, pegue a solicitação como HttpServletRequest, use a biblioteca fileachepload do Apache commons para analisar a solicitação do método PUT e processe o arquivo. Aqui estão alguns exemplos de código:

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

Em Config.groovy

Verifique se o multipart está ativado,

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

No controlador, adicione o método Post

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'}

com isso, consegui fazer o upload do arquivo, nada relacionado ao Spring Security.

2
Nazeel