Tuesday, January 10, 2012

Using a MultpartRequestResolver with Spring and using Spring Security concurrently

When using Spring Security, the CommonsMultipartResolver will not work. Why? Because the MultipartHttpServletRequest will be wrapped in a SecurityContextHolderAwareRequestWrapper, and will not be matched.

Of course, we don't want to fall back to just taking an HttpServletRequest as a parameter in our RequestMapping and parsing it out, we need to work smarter than that!

The best solution I could come up with is registering a custom WebArgumentResolver (below). But any readers out there have a better solution, please share!

Resolver:

public class SecurityContextWrappedMultipartRequestArgumentResolver implements WebArgumentResolver {

    private final CommonsMultipartResolver commonsMultipartResolver;

    public SecurityContextWrappedMultipartRequestArgumentResolver(){
        this.commonsMultipartResolver = new CommonsMultipartResolver();
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
        if (MultipartHttpServletRequest.class.equals(methodParameter.getParameterType())) {
            Object object = webRequest.getNativeRequest();
            if (! (object instanceof SecurityContextHolderAwareRequestWrapper)) {
                return UNRESOLVED;
            }
            HttpServletRequest request = (HttpServletRequest) object;
            if (!ServletFileUpload.isMultipartContent(request)) {
                return UNRESOLVED;
            }
            SecurityContextHolderAwareRequestWrapper requestWrapper = (SecurityContextHolderAwareRequestWrapper) request;
            return commonsMultipartResolver.resolveMultipart(requestWrapper);
        }
        return UNRESOLVED;
    }
}

Then we just wire it up into our HandlerAdapter (your config may vary):

    @Bean
    public HandlerAdapter handlerAdapter() {
        final AnnotationMethodHandlerAdapter handlerAdapter = new AnnotationMethodHandlerAdapter();
        handlerAdapter.setCustomArgumentResolver(new SecurityContextWrappedMultipartRequestArgumentResolver());
        handlerAdapter.setAlwaysUseFullPath(true);
        List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>();
        converterList.addAll(Arrays.asList(handlerAdapter.getMessageConverters()));
        converterList.add(jibxHttpMessageConverter);
        converterList.add(gsonHttpMessageConverter);
        converterList.add(csvLocalizationConverter);
        converterList.add(protobufLocalizationConverter);
        handlerAdapter.setMessageConverters(converterList.toArray(new HttpMessageConverter[converterList.size()]));
        return handlerAdapter;
    }

0 comments:

Post a Comment