#maven #spring-security #integration-testing
#maven #spring-безопасность #интеграция-тестирование
Вопрос:
Я хотел бы запустить Spring Security в двух средах: тестовой среде и производственной среде.
Я попытался создать конфигурацию для производственной среды:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private static Logger logger = LoggerFactory.getLogger(WebSecurityConfiguration.class);
@Autowired
CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
И один для тестовой среды интеграции:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
public class WebSecurityTestConfiguration extends WebSecurityConfigurerAdapter {
private static Logger logger = LoggerFactory.getLogger(WebSecurityConfiguration.class);
@Autowired
RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("stephane").password("mypassword").roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
Эти два класса находятся в разных источниках, один в src / main / java и один в src / test / java, но у них одинаковое имя пакета.
Сборка Maven дает мне следующее исключение:
Caused by: java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 100 was already used, so it cannot be used on com.thalasoft.learnintouch.rest.config.WebSecurityConfiguration$$EnhancerByCGLIB$$2d511ca8@536972 too.
Является ли причиной того, что повторное расширение WebSecurityConfigurerAdapter дважды является причиной того, что попытка создания экземпляра WebSecurityConfiguration снова завершается неудачей?
Как тогда это сделать?
Ответ №1:
Я мог бы решить проблему, добавив @Order(2) в WebSecurityConfigurerAdapter производственной среды и @Order(1) в тестовую среду.
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
@Order(2)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
}
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
@Order(1)
public class WebSecurityTestConfiguration extends WebSecurityConfigurerAdapter {
}
РЕДАКТИРОВАТЬ: лучшим решением было избежать использования аннотации @Order, которая сама по себе является признаком беспорядочной конфигурации.
Проблема была связана с загрузкой как WebSecurityConfiguration, так и WebSecurityTestConfiguration при выполнении тестов, когда требовалось загрузить только один из них, WebSecurityTestConfiguration.
С помощью условной аннотации было легко загрузить только требуемую.
Вот интерфейс определения условия:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Conditional(EnvNotTestCondition.class)
public @interface EnvNotTest {
}
И вот его реализация:
public class EnvNotTestCondition implements Condition {
private static final String ENV_TEST = "test";
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("env") == null || !context.getEnvironment().getProperty("env").equals(ENV_TEST);
}
}