Использование нескольких WebSecurityConfigurerAdapter в spring для загрузки

У меня есть 2 класса, которые расширяют WebSecurityConfigurerAdapter. И не могут заставить их работать вместе.

Идея такова:

  • Есть один WebSecurityConfigurerAdapter, который добавляет специальный фильтр в цепочку безопасности. Фильтр выполняет некоторую пользовательскую аутентификацию и сохраняет Authentication в SecurityContext. Это нормально работает. Конфигурируется следующим образом (импорт пропущен):
 @Order(1)
 @Configuration
 @EnableWebMvcSecurity
 public class BestSecurityConfig extends WebSecurityConfigurerAdapter {

     @Autowired
     private BestPreAuthenticationFilter ssoAuthenticationFilter;

     @Bean
     protected FilterRegistrationBean getSSOAuthenticationFilter() {
         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(ssoAuthenticationFilter);

         // Avoid include to the default chain
         filterRegistrationBean.setEnabled(false);

         return filterRegistrationBean;
     }

     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http
            .addFilterAfter(ssoAuthenticationFilter, SecurityContextPersistenceFilter.class);

     }

     @Configuration
     protected static class AuthenticationConfiguration extends
             GlobalAuthenticationConfigurerAdapter {

         @Autowired
         private BestAuthenticationProvider authenticationProvider;

         @Override
         public void configure(AuthenticationManagerBuilder auth) throws Exception {
             auth.authenticationProvider(authenticationProvider);
         }
     }
 }
  1. Я хочу, чтобы вышеуказанное было своего рода классом библиотеки, который любой может включать через @ComponentScan, и получить упорядоченную проверку подлинности. Очевидно, что они хотят предоставить пользовательский HttpSecurity для защиты информационных точек. Попробуйте что-то вроде:
 @Configuration
 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
 @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
 public class SecurityConfig extends WebSecurityConfigurerAdapter {

     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http
             .csrf().disable()
             .authorizeRequests()
             .antMatchers("/testUrl").hasRole("NON_EXISTING")
             .anyRequest().authenticated();
     }
 }

Очевидно, что тестовый URL-адрес не должен быть доступен, так как мой пользователь не является членом роли NON_EXISTING. К несчастью, она.

Если я переведу часть безопасности authorizeRequests() в форму класса конфигурации 1. рядом с добавлением фильтра безопасности, он блокирует доступ, как ожидалось. Но в моем случае это выглядит как вторая конфигурация игнорируется.

Я также отлаживал методы configure() и заметил, что HttpSecurity - это не тот же объект, который немного пахнет.

Любые советы, как я могу сделать эту работу высоко оцененной.

Подведите итог цели:

  • имеет один WebSecurityConfigurerAdapter, который добавляет фильтр и скрыт от пользователя библиотеки
  • позволяет пользователю определить собственную пользовательскую безопасность конечных точек.

Spring boot 1.1.6-RELEASE

Ответы

Ответ 1

Определите специальный интерфейс

public interface ServiceWebSecurityConfigurer {
    void configure(HttpSecurity http) throws Exception;
}

Затем выберите только один ConfigurerAdapter:

public class MyConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    ServiceWebSecurityConfigurer serviceSecConfig;

    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests(). // whatever

        if (serviceSecConfig != null) serviceSecConfig.configure(http);

        http.authorizeRequests(). // whatever
    }
}

а затем просто реализуйте ServiceWebSecurityConfigurer в другом месте, когда это необходимо. Также может быть несколько реализаций, просто соедините их автоматически в виде списка и итерируйте и используйте их все в вашей основной конфигурации.

Ответ 2

Итак, один из вариантов, который я только что нашел, это:

  • Удалите аннотацию @Configuration с первого bean

И измените 2. на:

 @Configuration
 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
 @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
 public class SecurityConfig extends BestSecurityConfig { //Note the changed extend !

     @Override
     protected void configure(HttpSecurity http) throws Exception {

         super.configure(http); // Merge of the 2 HTTP configurations

         http
             .csrf().disable()
             .authorizeRequests()
             .antMatchers("/testUrl").hasRole("NON_EXISTING")
             .anyRequest().authenticated();
     }
 }

Любые комментарии относительно того, правильно ли это или неправильно подход

Изменить: Через несколько лет я все еще не нашел другого пути, но мне все больше нравится этот путь. Даже в случае по умолчанию вы расширяете абстрактный WebSecurityConfigurerAdapter, нет причин, по которым какой-либо другой уровень абстракции не может предоставить другое абстрактное расширение, которое обеспечивает значимые значения по умолчанию.

Ответ 3

Я основал (на мой взгляд) более чистый способ структурирования некоторых конфигураций по умолчанию и упростил интеграцию в новые проекты с помощью пользовательских DSL.

Я использую его для настройки фильтров проверки подлинности JWT, но я думаю, что фильтр CORS более прост и дидактичен:

public class CustomCorsFilterDsl extends AbstractHttpConfigurer<CustomCorsFilterDsl, HttpSecurity> {

    @Override
    public void init(HttpSecurity http) throws Exception {
        //your init code here, no needed in this case
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        CorsFilter corsFilter = corsFilter(corsProperties);
        http.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class);
    }

    private CorsFilter corsFilter(CorsProperties corsProperties) {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:9000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("GET, POST, PUT, PATCH, DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

    public static CustomCorsFilterDsl dsl() {
        return new CustomCorsFilterDsl();
    }
}

И в вашем WebSecurityConfig вы можете использовать его следующим образом:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/foo/**").permitAll()
                //... your configurations
                .antMatchers("/**").authenticated()
                .and()
                .apply(CustomCorsFilterDsl.dsl());
    }
}

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