【问题标题】:Spring Boot Testing: Cannot Autowire springSecurityFilterChain on Test ClassSpring Boot 测试:无法在测试类上自动装配 springSecurityFilterChain
【发布时间】:2014-07-30 17:52:18
【问题描述】:

在 Spring Boot 下设置测试上下文时,我仍在努力使用各种注释。

我一直在参考this article,它对于如何处理Spring Boot下的各种上下文非常清晰。剩下的问题是,我似乎找不到一个注释组合,可以使springSecurityFilterChain主应用程序上下文(从这里驱动)中都可见:

@EnableAutoConfiguration
@ComponentScan
public class Application {

    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }

}

从这里开始的测试应用上下文:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestPersistenceConfig.class,MvcConfig.class,SecurityConfig.class},loader=AnnotationConfigContextLoader.class)
//@SpringApplicationConfiguration(classes = {TestPersistenceConfig.class,MvcConfig.class,SecurityConfig.class})
@WebAppConfiguration
public class ApplicationIntegrationTest {

    MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;

    //@Resource(name="springSecurityFilterChain")
    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    @Autowired
    private UserDao userDao;

    @Autowired
    private ClientDao clientDao;

    @Autowired
    private RoleDao roleDao;


    UUID key = UUID.fromString("f3512d26-72f6-4290-9265-63ad69eccc13");


    @Before
    public void setup() {

        // using the web application to initate the mock
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilter(springSecurityFilterChain).build();

        // our other choice is using another controller config
        //mockMvc = MockMvcBuilders.annotationConfigSetup(ExampleApplicationContext.class).build();

        // here we should build up the data structure using hibernate
        List<Client> clients = new ArrayList<>();

        Client clientEN = new Client();
        clientEN.setDeviceId("444444444");
        clientEN.setLanguage("en-EN");
        clientEN.setAgentId("444444444|68:5b:35:8a:7c:d0");
        Client clientENDomain = clientDao.save(clientEN);
        clients.add(clientENDomain);

        List<Role> roles = new ArrayList<>();
        Role roleUser = new Role();
        roleUser.setRole("user");
        Role roleUserDomain = roleDao.save(roleUser);
        roles.add(roleUserDomain);

        Role roleAdmin = new Role();
        roleAdmin.setRole("admin");
        Role roleAdminDomain = roleDao.save(roleAdmin);
        roles.add(roleAdminDomain);

        User user = new User();
        user.setLogin("user");
        user.setPassword("password");
        user.setClients(clients);
        user.setRoles(roles);

        userDao.save(user);

    }

    @Test
    public void thatViewBootstrapUsesHttpNotFound() throws Exception {

        // testing that a correct login into the form will result in a cookie being set
        MvcResult result = mockMvc.perform(post("/login")
                .param("username", "user").param("password", "password")).andReturn();
        Cookie c = result.getResponse().getCookie("my-cookie");

        Cookie[] cookies = result.getResponse().getCookies();
        for (int i = 0; i <= cookies.length; i++) {
            System.out.println("cookie " + i + " name: " + cookies[i].getName());
            System.out.println("cookie " + i + " value: " + cookies[i].getValue());
        }
        //assertThat(c.getValue().length(), greaterThan(10));

        // No cookie; 401 Unauthorized
        mockMvc.perform(get("/")).andExpect(status().isUnauthorized());

        // With cookie; 200 OK
        mockMvc.perform(get("/").cookie(c)).andExpect(status().isOk());

        // Logout, and ensure we're told to wipe the cookie
        result = mockMvc.perform(delete("/session")).andReturn();
        c = result.getResponse().getCookie("my-cookie");
        assertThat(c.getValue().length(), is(0));
    }

}

顺便说一句,@SpringApplicationConfiguration 似乎在任何情况下都不起作用,这与 doco 相反。安全配置如下:

@Configuration
@EnableWebMvcSecurity
@ComponentScan({
        "com.touchcorp.touchpoint.security",
        "com.touchcorp.touchpoint.service",
        "com.touchcorp.touchpoint.model.dao"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    DeviceUsernamePasswordAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {


        auth
                .authenticationProvider(customAuthenticationProvider);
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/**")
                    .authorizeRequests()
                .anyRequest().hasRole("ADMIN")
                    .and()
                    .httpBasic();
        }
    }

    @Order(2)
    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .csrf().disable()
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                .loginPage("/login")
                    .failureUrl("/login?error=1")
                    .permitAll()
                    .and()
                .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/");
        }
    }

    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
                .addResourceHandler("/resources/**")
                .addResourceLocations("/resources/")
                .setCachePeriod(31556926);
    }

}

谁能看到为什么springSecurityFilterChain 是不可见的(“没有找到FileterChainProxy 类型的bean”)。谢谢,我要拔头发了。

我想我只是有点不清楚所有注释的目的。 Spring Boot 参考很好,但它并没有真正超出既定基线。似乎一旦你必须将 spring security、hibernate 和 mvc 结合在一起,它就开始变得复杂,不清楚要做什么。

【问题讨论】:

  • 看起来像上下文父子问题。您不能自动装配在父上下文的子上下文中创建的 bean,但反过来也可以
  • 谢谢 gerrytan,但我不确定你在说什么
  • 这不是父上下文问题,因为只有一个上下文。

标签: spring-mvc spring-security spring-boot


【解决方案1】:

我会担心为什么 @SpringApplicationConfiguration 不起作用,因为它在其他地方被广泛使用(例如在 Spring Boot 示例中)并且在那里运行良好。也许是类路径问题?链接到其他人可以尝试重现您的问题的完整项目怎么样?

您有 2 个不同的应用程序上下文(一个用于测试,一个用于您的 Application),因此如果它们的行为不同也就不足为奇了。特别是Application@EnableAutoConfiguration 而你测试(据我们所知)没有,所以有一个值得研究的区别。但测试显然没有任何问题。

这是一个自动连接安全过滤器的测试示例:https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/test/java/org/springframework/security/samples/config/ApplicationConfigurationTests.java。有用。这是另一个:https://github.com/cloudfoundry/uaa/blob/master/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMvcMockTests.java

【讨论】:

  • 我说得太早了。看来 springSecurityFilterChain 毕竟并没有逃避配置。相反,似乎正在发生的是一个新的、普通的 springSecurityFilterChain 在测试中自动装配,而不是在 TestPersistenceConfig 下设置的那个。结果是 UsernamePasswordAuthenticationFilter 触发而不是我的 DeviceUsernamePasswordAuthenticationFilter。
【解决方案2】:

感谢戴夫·赛尔,

我做了一些更改,似乎可以解决各种缺失的部分:

一个以:

开头的测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestApplicationConfig.class,TestPersistenceConfig.class,MvcConfig.class,SecurityConfig.class},loader=AnnotationConfigWebContextLoader.class)
@WebAppConfiguration
public class ApplicationIntegrationTest {

和一个“标记”配置类,它充当组件扫描器:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.touchcorp.touchpoint"})
public class TestApplicationConfig {
}

除了数据层之外,所有 pars 似乎都可以工作,它无法找到我的任何域对象,但这似乎仅限于 JPA/Hibernate 配置,而不是应用程序问题。

再次感谢。

【讨论】:

    猜你喜欢
    • 2020-03-24
    • 2020-02-09
    • 1970-01-01
    • 2016-03-29
    • 2021-12-23
    • 2020-06-22
    • 2014-03-11
    • 2018-04-15
    • 1970-01-01
    相关资源
    最近更新 更多