web-dev-qa-db-fra.com

Demandes de sécurité et multiparties de printemps

J'ai un @Controller protégé par Spring Security et OAuth2 dans lequel j'essaie de permettre à mes utilisateurs de télécharger un fichier:

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

Lorsque j'essaie de télécharger un fichier et un titre, j'obtiens l'exception suivante. Je configure l'en-tête Content-Type sur multipart/form-data.

Java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ org.Apache.catalina.connector.RequestFacade@1aee75b7]]
    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)

Comment puis-je effectuer des téléchargements de fichiers derrière Spring Security? Il semble que la demande ne soit jamais transformée en MultiPartHttpServerRequest et qu'elle ne fonctionne donc pas?

Si je change ma signature de méthode pour prendre un @RequestParam MultipartFile, alors j'obtiens une exception comme:

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)

... mais j'ai un MultipartResolver configuré dans mon XML:

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

J'ai vu ce billet de blog sur le fonctionnement de Spring 3. - mais j'essaie de rester plus à jour et j'utilise 3.1 actuellement. Y a-t-il peut-être un correctif mis à jour?

23
Matthew Runo

Le problème est que j'utilise un PUT au lieu d'un POST. Commons FileUpload est codé en dur pour accepter uniquement POST demandes de fichiers.

Vérifiez la méthode isMultipartContent là. Pour résoudre ce problème, utilisez un POST ou étendez cette classe et remplacez cette méthode pour travailler comme vous le souhaitez.

J'ai ouvert FILEUPLOAD-214 pour ce problème.

25
Matthew Runo

Pour résoudre le problème, n'utilisez pas Spring MultiPartHttpServerRequest, au lieu de cela, prenez la demande en tant que HttpServletRequest, utilisez la bibliothèque Apache commons fileupload pour analyser la demande de la méthode PUT et traitez le fichier. Voici quelques exemples de code:

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

Dans Config.groovy

Assurez-vous que le multipart est activé,

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

Dans le contrôleur, ajoutez la méthode 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'}

avec ceux-ci, j'ai pu télécharger le fichier, rien lié à Spring Security.

2
Nazeel