我想在两个环境中运行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失败了?
如何去做呢?
答案 0 :(得分:3)
我可以通过将@Order(2)添加到生产环境WebSecurityConfigurerAdapter和@Order(1)到测试环境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);
}
}