简体   繁体   English

Testing Spring rest controller with Spring Security OAuth

[英]Testing Spring rest controller with Spring Security OAuth

I'm trying to test my controller with Spring boot @WebMvcTest.我正在尝试使用 Spring 引导 @WebMvcTest 测试我的 controller。 I also have implemented SPring OAuth security (resource and authorization server), so to reach endpoint you need to be authorized.我还实现了 SPring OAuth 安全性(资源和授权服务器),因此要到达端点,您需要获得授权。

For this reason I cannot test my controller like this:出于这个原因,我不能像这样测试我的 controller:

@WebMvcTest(MyController.class)
public class MyControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private MyService service;

    @Test
    public void myTest() throws Exception {
        //Arrange request
        
        //Act
        mvc.perform
            (MockMvcRequestBuilders
                .post("/v1/my-controller/type", type.name())
                .characterEncoding(StandardCharsets.UTF_8.name())
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(requestDTO)))
            //Assert
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(content().json(objectMapper.writeValueAsString("")));

    }

Because it requires resource server.因为它需要资源服务器。 But the problem is that when I'm running this test I got next error:但问题是,当我运行这个测试时,我得到了下一个错误:

    ***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.danfoss.cloud.prosa.restapi.security.WebSecurityConfig$OAuthResourceServer required a bean of type 'org.springframework.security.oauth2.provider.token.TokenStore' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.security.oauth2.provider.token.TokenStore' in your configuration.

My Resource server looks like我的资源服务器看起来像

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Configuration
    @EnableResourceServer
    public static class OAuthResourceServer extends ResourceServerConfigurerAdapter {

         
        private final TokenStore tokenStore;
        ////CANNOT INJECT DURING WEB CONTEXT START
        @Autowired
        public OAuthResourceServer(TokenStore tokenStore) {
            this.tokenStore = tokenStore;
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources
                    .resourceId("resource")
                    .tokenStore(tokenStore);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .antMatchers("/status")
                .permitAll()
                .anyRequest()
                .access("isAuthenticated()");
        }

        private String createAuthorizationExpression(String ipWhitelist) {
            return null;
        }
    }
}

One important thing that application works fine and it injects TokenStore fine during run.应用程序运行良好并且在运行期间可以正常注入 TokenStore 的一件重要事情。

How to overcome this issue?如何克服这个问题?

Resolved this issue by decoupling configurations like this:通过解耦配置解决了这个问题,如下所示:

@Configuration
public class Config {

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(mainDataSource());
    }

               ....
    other beans
}

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

@Configuration
@EnableWebSecurity
@EnableResourceServer
public class OAuthResourceServer extends ResourceServerConfigurerAdapter {

    private final TokenStore tokenStore;


    @Autowired
    public OAuthResourceServer(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources
            .resourceId("resource")
            .tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers(
                "/status",
                "/")
            .permitAll()
            .anyRequest()
            .access(
                            ...
                        );
    }


}

@Configuration
@EnableAuthorizationServer
public class OAuthAuthorizationServer extends AuthorizationServerConfigurerAdapter {

        ...
    private final AuthenticationManager authenticationManager;
      ...
    private final TokenStore tokenStore;
     ...


    @Autowired
    public OAuthAuthorizationServer(
    ....
        AuthenticationManager authenticationManager,
        TokenStore tokenStore,
    ...
    ) {
        this.restUserDetailsService = restUserDetailsService;
        this.oAuthRestAuthenticationProvider = oAuthRestAuthenticationProvider;
        this.authenticationManager = authenticationManager;
        this.jdbcClientDetailsService = jdbcClientDetailsService;
        this.tokenStore = tokenStore;
        this.authorizationCodeServices = authorizationCodeServices;
    }

    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
        tokenServices.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setReuseRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);
        tokenServices.setClientDetailsService(jdbcClientDetailsService);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setAuthenticationManager(authenticationManager);
        return tokenServices;
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(oAuthRestAuthenticationProvider);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(jdbcClientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
            .approvalStoreDisabled()
            .authorizationCodeServices(authorizationCodeServices)
            .tokenStore(tokenStore)
            .tokenServices(tokenServices())
            .authenticationManager(authenticationManager)
            .userDetailsService(restUserDetailsService);
    }
}

Then to disable security in controller test you need to do next然后在 controller 测试中禁用安全性,您需要执行下一步

@WebMvcTest(MyController.class)
@AutoConfigureMockMvc(addFilters = false)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM