测试和生产环境中的Spring Security

时间:2014-06-23 23:18:53

标签: maven spring-security integration-testing

我想在两个环境中运行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 个答案:

答案 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);
    }

}