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

CharacterEncodingFilter не работает вместе с Spring Security 3.2.0

Я новичок в инфраструктуре MVC Spring, и у меня есть проблема, которую я не могу решить самостоятельно. Все началось, когда я интегрировал защиту Spring с моим приложением, после чего все значения unicode из HTML-формы не были закодированы (безопасность spring работает правильно). Я пришел к выводу, что это происходит, вероятно, потому, что мой DelegatingFilterProxy называется первым фильтром в цепочке.

Вот моя конфигурация, которая, как я думал, будет работать, но это не так:

1) Я расширяю AbstractSecurityWebApplicationInitializer - из javadoc:

Registers the DelegatingFilterProxy to use the springSecurityFilterChain() before any
other registered Filter.

Из этого класса я также переопределяю метод beforeSpringSecurityFilterChain, который касается javadoc:

Invoked before the springSecurityFilterChain is added.

Итак, я подумал, что это будет лучшее место для регистрации CharacterEncodingFilter:

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "true");
        characterEncodingFilter.addMappingForUrlPatterns(null, true, "/*");
    }
}

Но это не работает.

Еще один вариант, который я устал, - это зарегистрировать фильтр через класс AbstractAnnotationConfigDispatcherServletInitializer, переопределив метод getServletFilters():

public class WebAppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    //{!begin addToRootContext}
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { SecurityConfig.class, DatabaseConfig.class, InternationalizationConfig.class };
    }
    //{!end addToRootContext}

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebAppConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {

        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        return new Filter[] { characterEncodingFilter};
    }
}

Но это не работает. Кто-нибудь сталкивается с той же проблемой или имеет некоторые идеи, как разрешить это?

Вот моя полная конфигурация для первого параметра, где я регистрирую фильтр кодирования через AbstractSecurityWebApplicationInitializer:

@Order(1)
public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "true");
        characterEncodingFilter.addMappingForUrlPatterns(null, true, "/*");
    }
}

@Order(2)
public class WebAppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    //{!begin addToRootContext}
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { SecurityConfig.class, DatabaseConfig.class, InternationalizationConfig.class };
    }
    //{!end addToRootContext}

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebAppConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

@EnableWebMvc
//@Import(value = {DatabaseConfig.class, InternationalizationConfig.class, SecurityConfig.class})
@ComponentScan(basePackages = {"com.ajurasz.controller", "com.ajurasz.service", "com.ajurasz.model"})
@Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {

    @Bean
    public UrlBasedViewResolver viewResolver() {
        UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
        urlBasedViewResolver.setViewClass(TilesView.class);
        urlBasedViewResolver.setContentType("text/html;charset=UTF-8");
        return urlBasedViewResolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer() {
        TilesConfigurer tilesConfigurer = new TilesConfigurer();
        tilesConfigurer.setDefinitions(new String[] {"/WEB-INF/tiles.xml"});
        return tilesConfigurer;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/**");
        registry.addResourceHandler("/documents/**").addResourceLocations("/WEB-INF/pdfs/documents/**");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        PageableHandlerMethodArgumentResolver pageableHandlerMethodArgumentResolver =
                new PageableHandlerMethodArgumentResolver();
        pageableHandlerMethodArgumentResolver.setFallbackPageable(new PageRequest(0, 4, new Sort(Sort.Direction.DESC, "id")));

        argumentResolvers.add(pageableHandlerMethodArgumentResolver);
    }
}

Зависимости:

spring -mvc 3.2.5.RELEASE

spring -security-config, spring -security-web, spring -security-core 3.2.0.RELEASE

Я работаю над этим по следующей ссылке: https://github.com/ajurasz/Manager

4b9b3361

Ответ 1

Иметь ту же проблему. Моим решением было использовать необработанный фильтр сервлета:

public void onStartup(ServletContext servletContext) throws ServletException {
      FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encoding-filter", new CharacterEncodingFilter());
      encodingFilter.setInitParameter("encoding", "UTF-8");
      encodingFilter.setInitParameter("forceEncoding", "true");
      encodingFilter.addMappingForUrlPatterns(null, true, "/*");
}

Обратите внимание, что эта проблема возникает только с Tomcat, но не с Jetty.

Ответ 2

Нам нужно добавить CharacterEncodingFilter перед фильтрами, которые впервые читают свойства запроса. Существует securityFilterChain (стоит второй после фильтра метрики), и мы можем добавить в него наш фильтр. Первый фильтр (внутри цепочки безопасности), который читает свойства, является CsrfFilter, поэтому перед этим он помещает CharacterEncodingFilter.

Краткое решение:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter,CsrfFilter.class);
        //rest of your code   
    }
//rest of your code
}

Ответ 3

В последнее время я столкнулся с той же проблемой, и ваша первая попытка на самом деле очень близка к решению, которое я использовал (здесь ваш код, исправлен):

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
    FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
    characterEncodingFilter.setInitParameter("encoding", "UTF-8");
    characterEncodingFilter.setInitParameter("forceEncoding", "true");
    characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
    }
}

Единственное отличие - это второй аргумент при добавлении фильтра для шаблонов URL. В Javadoc для этого параметра указано:

isMatchAfter - true, если заданное сопоставление фильтра должно быть сопоставлено после любых объявленных сопоставлений фильтра, а false, если оно должно быть сопоставлено перед любыми объявленными сопоставлениями фильтров ServletContext, из которых была получена эта фильтрационная регистрация.

Таким образом, установка его в false должна чисто решить вашу проблему (без какого-либо XML).

Ответ 4

Я не знаю, в чем проблема, но я бы никогда не сконфигурировал такой простой фильтр внутри Spring. Скорее сделайте это правильно в web.xml - легче разрабатывать, понимать и отлаживать.

  <!-- Hint: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q8 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Важно: настройте это сопоставление фильтра перед цепочкой фильтров Spring (т.е. перед отображением фильтра для DelegatingFilterProxy).

Ответ 5

Я использовал

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter,CsrfFilter.class);
        //rest of your code   
    }
//rest of your code
}

Ответ 6

Мне не нравятся ответы, опубликованные до сих пор, потому что либо используют неявные классы Spring, либо полагаются на детали реализации.

По-моему, все должно работать, просто определяя стандартный @Bean с высоким @Order, так что это ошибка загрузки - но, к счастью, все работает как ожидалось (?), если мы используем FilterRegistrationBean вместо простого Filter (я использую Boot 1.1.5):

@Bean
public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
    registrationBean.setFilter(characterEncodingFilter);
    characterEncodingFilter.setEncoding("UTF-8");
    characterEncodingFilter.setForceEncoding(true);
    registrationBean.setOrder(Integer.MIN_VALUE);
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
}