Миграция с Spring 5 на Spring 6: Проблема с springSecurityFilterChain

Вопрос или проблема

В настоящее время я переношу приложение Spring JSF с Spring 5 на последнюю версию Spring 6. Я использую Java 17 с версией spring-boot-starter-parent 3.3.5 и версией Spring Security 6.3.4.

В предыдущей версии у нас была следующая конфигурация в web.xml для springSecurityFilterChain:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>*.jsf</url-pattern>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

Сейчас мы преобразуем эту конфигурацию в конфигурацию на основе Java, используя Spring Boot. Вот соответствующее определение Bean в нашем классе WebConfig:

@Bean 
public FilterRegistrationBean<DelegatingFilterProxy> springSecurityFilterChain() { 
    FilterRegistrationBean<DelegatingFilterProxy> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new DelegatingFilterProxy("springSecurityFilterChain"));
    registrationBean.addUrlPatterns("*.jsf", "*.jsp"); 
    return registrationBean;
} 

Однако я сталкиваюсь со следующей ошибкой во время запуска приложения:

org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании бина с именем 'springSecurityFilterChain': неудовлетворенная зависимость, выраженная через параметр конструктора 0: Не удалось преобразовать значение аргумента типа [java.util.ArrayList] в требуемый тип [java.util.List]: Не удалось преобразовать значение типа 'java.util.ArrayList' в требуемый тип 'java.util.List'; Невозможно преобразовать значение типа 'org.springframework.boot.web.servlet.FilterRegistrationBean' в требуемый тип 'jakarta.servlet.Filter': не найдены подходящие редакторы или стратегия преобразования
    в org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:757) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.14.jar:6.1.14]
    в org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.14.jar:6.1.14]
    в org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.14.jar:6.1.14]
    в org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.5.jar:3.3.5]
    в org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-3.3.5.jar:3.3.5]
    в org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) [spring-boot-3.3.5.jar:3.3.5]
    в org.springframework.boot.SpringApplication.run(SpringApplication.java:335) [spring-boot-3.3.5.jar:3.3.5]

Похоже, что Spring пытается преобразовать FilterRegistrationBean в jakarta.servlet.Filter, что и вызывает проблему.

Вопрос:

Как правильно определить Bean springSecurityFilterChain в Spring 6, чтобы избежать этой ошибки преобразования?

Дополнительная информация:

  • Версия Java: 17
  • Версия Spring Boot: 3.3.5
  • Версия Spring Security: 6.3.4

Любая помощь или руководство будут очень полезны!

Ответ или решение

При миграции вашего приложения с использованием Spring 5 на Spring 6 может возникнуть ряд проблем, связанных с настройками безопасности, особенно в аспектах фильтров Servlet. Рассмотрим ваше конкретное сообщение об ошибке и подход к корректной настройке канала фильтров Spring Security.

Проблема и анализ

Вы столкнулись с исключением UnsatisfiedDependencyException, которое указывает на ошибку во время создания бина springSecurityFilterChain. Конкретно, проблема заключается в попытке конвертировать FilterRegistrationBean в jakarta.servlet.Filter. Это связано с тем, что в Spring 6 изменились некоторые подходы к конфигурации и обработке фильтров.

Решение

Вместо использования DelegatingFilterProxy напрямую, мы можем воспользоваться стандартным подходом Spring для настройки безопасности, подстраиваясь под новый синтаксис и стили управления. Настройка фильтров в Spring Boot выглядит несколько иначе по сравнению с традиционным XML.

  1. Убедитесь, что ваш проект уже включает зависимости для Spring Security. В файле pom.xml или build.gradle должны быть правильно указаны версии:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>3.3.5</version>
    </dependency>
  2. Определите SecurityFilterChain в вашем классе конфигурации:

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.web.SecurityFilterChain;
    
    @Configuration
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .requestMatchers("*.jsf", "*.jsp").authenticated()
                .and()
                .formLogin()
                .and()
                .logout()
                .permitAll();
            return http.build();
        }
    }

Настройка фильтра

При таком подходе вам не нужно отдельно регистрировать springSecurityFilterChain как фильтр, так как Spring Security автоматически обрабатывает это для вас через SecurityFilterChain. Вам просто нужно будет настроить, какие URL шаблоны должны быть защищены, и как именно.

Исправление ошибок преобразования

На основании вашего сообщения об ошибке, вам, вероятно, больше не нужно использовать FilterRegistrationBean для DelegatingFilterProxy. При правильной конфигурации SecurityFilterChain будет автоматически зарегистрирован как нужный фильтр.

Подводя итоги

В результате обновления конфигурации безопасности до Java-базированной методологии, вы устраняете ошибку преобразования и используете современные практики управления безопасностью в Spring 6. Этот подход обеспечит не только исправление возникших ошибок, но и новый уровень гибкости и поддержки в будущем.

Если у вас останутся вопросы или возникнут дополнительные проблемы, пожалуйста, не стесняйтесь обращаться за помощью, и мы постараемся вам помочь!

Оцените материал
Добавить комментарий

Капча загружается...