Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 集成测试RestController时禁用或模拟Spring安全筛选器_Java_Spring_Spring Security_Integration Testing - Fatal编程技术网

Java 集成测试RestController时禁用或模拟Spring安全筛选器

Java 集成测试RestController时禁用或模拟Spring安全筛选器,java,spring,spring-security,integration-testing,Java,Spring,Spring Security,Integration Testing,在我的应用程序中,我在WebSecurity配置适配器扩展中添加了一个自定义过滤器: @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private static final RequestMatcher PROTECTED_URLS = new AntPathRequestMatcher("/v1/**"); @Overri

在我的应用程序中,我在WebSecurity配置适配器扩展中添加了一个自定义过滤器:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private static final RequestMatcher PROTECTED_URLS = new AntPathRequestMatcher("/v1/**");

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .requestMatchers(PROTECTED_URLS)
                .authenticated()
            .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .logout().disable();
    }

    @Bean
    AuthenticationFilter authenticationFilter() throws Exception {
        final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);

        // filter setup...

        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }
}
负责通过调用外部授权服务器验证访问令牌的筛选器本身定义为:

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    AuthenticationFilter(final RequestMatcher requiresAuth) {
        super(requiresAuth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
                                                HttpServletResponse httpServletResponse)
        throws AuthenticationException, IOException, OAuth2Exception {
        try {
            // Get Authorization header.
            String token = httpServletRequest.getHeader(AUTHORIZATION);

            // Check if the token is valid by calling an external authorization server.
            // Returns some Authentication if successful.
        } catch (OAuth2Exception exception) {
            // Return 401
        } catch (Exception exception) {
            // All other errors are 500s
        }
    }

    @Override
    protected void successfulAuthentication(final HttpServletRequest request,
                                            final HttpServletResponse response,
                                            final FilterChain chain,
                                            final Authentication authResult)
        throws IOException, ServletException {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request, response);
    }
}
@RestController
@RequestMapping(value = "/v1", produces = "application/json")
public class SomeController {

    @Autowired
    private SomeService someService;

    @ResponseStatus(OK)
    @PostMapping(value = "/a/path")
    public SomeSuccessResponse pathHandlerMethod() {
        return someService.someServiceMethod();
    }
}
我尝试在控制器上执行集成测试,定义如下:

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    AuthenticationFilter(final RequestMatcher requiresAuth) {
        super(requiresAuth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
                                                HttpServletResponse httpServletResponse)
        throws AuthenticationException, IOException, OAuth2Exception {
        try {
            // Get Authorization header.
            String token = httpServletRequest.getHeader(AUTHORIZATION);

            // Check if the token is valid by calling an external authorization server.
            // Returns some Authentication if successful.
        } catch (OAuth2Exception exception) {
            // Return 401
        } catch (Exception exception) {
            // All other errors are 500s
        }
    }

    @Override
    protected void successfulAuthentication(final HttpServletRequest request,
                                            final HttpServletResponse response,
                                            final FilterChain chain,
                                            final Authentication authResult)
        throws IOException, ServletException {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request, response);
    }
}
@RestController
@RequestMapping(value = "/v1", produces = "application/json")
public class SomeController {

    @Autowired
    private SomeService someService;

    @ResponseStatus(OK)
    @PostMapping(value = "/a/path")
    public SomeSuccessResponse pathHandlerMethod() {
        return someService.someServiceMethod();
    }
}
最后,我的测试设置如下所示:

@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
@Import(SecurityConfig.class)
@ContextConfiguration
@WebAppConfiguration
public class SomeControllerTest {

    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private WebApplicationContext context;

    @MockBean
    private SomeService someService;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity()) // When I comment out this line I'm getting 404 errors instead.
            .build();
    }

    @Test
    @WithMockUser
    public void performIntegrationTest() throws Exception {
        mockMvc.perform(post("/v1/a/path")).andExpect(status().isOk());
    }
}
我希望在这种情况下关闭身份验证或以某种方式模拟身份验证—根本不应调用
AuthenticationFilter
中的实际代码。为了实现这一点,在
SomeControllerTest
类中,我尝试了:

  • @WithMockUser
  • 使用
    MockMvcBuilders
    设置
    mockMvc
    (请参阅上面的
    setup()
    方法)使用
    。应用(springSecurity())
    和不使用它
  • @AutoConfigureMockMvc
    注释
    SomeControllerTest
    类(同时将
    安全
    添加过滤器
    参数设置为
  • @ContextConfiguration
    @WebAppConfiguration
    注释
    SomeControllerTest
    类(我不知道它是否改变了什么)

这些方法都没有禁用身份验证。当我运行测试时,调用外部服务的
AuthenticationFilter
attemptAuthentication()
方法仍然被调用,这是我不希望发生的。

禁用过滤器听起来与集成测试相矛盾,imho。您是否考虑过模拟过滤器

创建一个

public class MockAuthenticationFilter implements Filter {
   // return mock data for different use cases. 
} 
然后在测试中注册此过滤器

@Before
public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(context)
        .apply(springSecurity(new MockAuthenticationFilter()))
        .build();
}


这还允许您测试过滤器以某种方式工作的不同用例

谢谢你的回答。在实现了一个空的mock身份验证过滤器并将其附加到mockMvc之后,我现在一直得到404。