java - 使用 Spring Security 进行 Spring Boot 测试。如何启动另一种安全配置?

标签 java spring spring-mvc spring-security spring-boot

我的 spring boot 应用程序有一个 Application 类。当我运行它(作为应用程序)时,它会在嵌入式 servlet 容器(在我的例子中是 Tomcat)中自行启动。不知何故(我想是通过应用程序的@annotations),加载了同一个包中的WebSecurityConfig(扩展WebSecurityConfigurerAdapter)。

WebSecurityConfig 包含两个重要的配置信息 block :

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableGlobalMethodSecurity(prePostEnabled = true) // enables method-level role-checking
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth
         .ldapAuthentication()
         .userSearchBase("CN=Users,DC=some,DC=domain,DC=com")   
         .userSearchFilter("(sAMAccountName={0})")
         .groupSearchBase("OU=Groups,DC=some,DC=domain,DC=com")                 
         .groupSearchFilter("(member={0})")
         .contextSource()
            .managerDn("cn=ad-bind,cn=users,dc=some,dc=domain,dc=com")
            .managerPassword("APASSWORD!") 
            .url("ldaps://some.domain.com:636");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
         System.out.println("***************** WebSecurityConfig.configure *************************");
         http.csrf().disable();

         http
            .headers()
                .frameOptions()
                    .disable();

         http
                .authorizeRequests()
                    .antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
                            .permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login").defaultSuccessUrl("/me")
                    .permitAll()
                    .and()
                    .logout()
                    .permitAll();

         http.logout().logoutSuccessUrl("/me");
    }
}

configureGlobal() 包含我们内部 LDAP 系统的配置,它工作得很好。

configure() 指定哪些 URL 是公开的,哪些只显示给登录用户,以及哪些相对 URL 在用户登录时发送给他们。

现在我正在进行集成测试并编写了一些方法来测试不需要身份验证的 Controller 。这些测试按预期工作。 Application 类启动并针对它执行测试。

但现在我想测试确实需要身份验证的 Controller 方法。我认为实现这一点的方法是告诉测试类启动另一个应用程序类(在我的例子中是 TestApplication)和创建虚拟用户的 WebSecurityConfig:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestApplication.class) // fires up with TestApplication.class instead of Application.class
@WebAppConfiguration
public class ProductControllerTests {
    // test methods here, this time with username/password included
}

@Configuration
@EnableAutoConfiguration
public class TestApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class<TestApplication> applicationClass = TestApplication.class;

}

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.inMemoryAuthentication().withUser("testuser").password("userpass").roles("USER");
      auth.inMemoryAuthentication().withUser("testadmin").password("adminpass").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
         System.out.println("***************** WebSecurityConfig.configure *************************");
         http.csrf().disable();

         http
            .headers()
                .frameOptions()
                    .disable();

         http
                .authorizeRequests()
                    .antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
                            .permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/login").defaultSuccessUrl("/me")
                    .permitAll()
                    .and()
                    .logout()
                    .permitAll();

         http.logout().logoutSuccessUrl("/me");
    }
}

所以我的问题是:当我执行单元测试类时,我相信 TestApplication 正在触发。但是,它没有选择替代的 WebSecurityConfig 类及其 auth.inMemoryAuthentication() 测试用户。 如何强制我的应用程序在正常运行时使用一个 WebSecurityConfig,而在运行单元测试时使用不同的 WebSecurityConfig?

最佳答案

您可以配置您的 TestApplication 以仅包含您想要测试的 beans。换句话说,确保您的 WebSecurityConfig 不是测试配置的一部分。如果您阅读 javadoc of @SpringBootApplication您会注意到它是一个复合注释,由(除其他外)@ComponentScan 组成注解。因此,您的 ApplicationTestApplication 将从类所在的包执行递归扫描。 Spring 引用文档有一个关于 Using filters to customize scanning 的特定章节.

或者,如果您使用的是 Spring Security 版本 4 或更高版本,您可能会发现添加了 @WithMockUser@WithUserDetails有趣。

关于java - 使用 Spring Security 进行 Spring Boot 测试。如何启动另一种安全配置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30603015/

相关文章:

java - 如何使用自定义登录页面纠正 Spring Security 异常?

java - 如何干净地测试使用 DomainClassConverter 检索参数的 Spring Controller ?

java - 生成 pdf PDFBox headless docker 容器失败

java - 从 C++ 到 java 的 Android JNI 回调

mysql - Spring MVC、MySQL 和 UTF-8

java - 断言错误失败

Java - 创建没有时区的日历

java - InnoSetup : Detect if Java is 32-bit or 64-bit

java - MapStruct/Java - 将时间戳转换为即时

java - 使用 Spring MVC 从数据库获取数据以显示在下拉列表中,例如国家、州、城市