2017-01-24 154 views
5

環境內: 我有由多個基礎設施服務和資源服務(包含業務邏輯)彈簧啓動基於微服務架構的應用程序。授權和身份驗證由管理用戶實體併爲客戶端創建JWT令牌的oAuth2服務處理。使用@WithMockUser(與@SpringBootTest)OAuth2用戶資源服務器應用

爲了測試其整體的單一微服務的應用程序,我試圖用TestNG的spring.boot.testorg.springframework.security.test建立測試...

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"spring.cloud.discovery.enabled=false", "spring.cloud.config.enabled=false", "spring.profiles.active=test"}) 
@AutoConfigureMockMvc 
@Test 
public class ArtistControllerTest extends AbstractTestNGSpringContextTests { 

    @Autowired 
    private MockMvc mvc; 

    @BeforeClass 
    @Transactional 
    public void setUp() { 
    // nothing to do 
    } 

    @AfterClass 
    @Transactional 
    public void tearDown() { 
    // nothing to do here 
    } 

    @Test 
    @WithMockUser(authorities = {"READ", "WRITE"}) 
    public void getAllTest() throws Exception { 

    // EXPECT HTTP STATUS 200 
    // BUT GET 401 
    this.mvc.perform(get("/") 
      .accept(MediaType.APPLICATION_JSON)) 
      .andExpect(status().isOk()) 
    } 
} 

其中安全(資源服務器)配置如下

@Configuration 
@EnableResourceServer 
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 

    // get the configured token store 
    @Autowired 
    TokenStore tokenStore; 

    // get the configured token converter 
    @Autowired 
    JwtAccessTokenConverter tokenConverter; 

    /** 
    * !!! configuration of springs http security !!! 
    */ 
    @Override 
    public void configure(HttpSecurity http) throws Exception { 
     http 
      .csrf().disable() 
      .authorizeRequests() 
      .antMatchers("/**").authenticated(); 
    } 

    /** 
    * configuration of springs resource server security 
    */ 
    @Override 
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 
    // set the configured tokenStore to this resourceServer 
    resources.resourceId("artist").tokenStore(tokenStore); 
    } 

} 

以及基於以下方法的安全檢查註釋IDE控制器類

@PreAuthorize("hasAuthority('READ')") 
@RequestMapping(value = "/", method = RequestMethod.GET) 
public List<Foo> getAll(Principal user) { 
    List<Foo> foos = fooRepository.findAll(); 
    return foos; 
} 

我認爲這會工作,但運行測試時,我只能得到一個斷言錯誤

java.lang.AssertionError: Status 
Expected :200 
Actual :401 


問題: 有一些完全明顯,我在做什麼錯誤?或者@WithMockUser不會在oAuth2環境中使用@SpringBootTest和@AutoConfigureMockMvc?如果是這種情況......作爲像這樣的(集成)測試的一部分,測試基於路由和方法的安全配置的最佳方法是什麼?


附錄: 我也嘗試了不同的方法,如類似下面的...但它導致了同樣的結果:(

this.mvc.perform(get("/") 
     .with(user("admin").roles("READ","WRITE").authorities(() -> "READ",() -> "WRITE")) 
     .accept(MediaType.APPLICATION_JSON)) 

看到
spring security testing
spring boot 1.4 testing

回答

4

@WithMockUser創造了SecurityContext中認證。 同樣適用於with(user("username"))

默認情況下,OAuth2AuthenticationProcessingFilter不使用SecurityContext,但始終使用令牌(「無狀態」)構建身份驗證。

您可以輕鬆地改變這種行爲可以在資源服務器安全配置的無狀態標誌設置爲false:

@Configuration 
@EnableResourceServer 
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 

    @Override 
    public void configure(ResourceServerSecurityConfigurer security) throws Exception { 
     security.stateless(false); 
    } 
} 

當然,標誌設置爲在您的測試環境,只。

+0

將此類添加到我的(maven項目)src/test/java對Spring Boot 1.5.4和1.5.9有幫助。我現在可以按照我的預期使用@WithMockUser。 – DaShaun

+0

將此類添加到我的項目允許我繞過安全性,但它似乎不像用戶重要。無論我給測試用戶的範圍如何,它總是通過安全。這是意圖嗎? – Rig

2

我有德sa我的問題,我發現這是創建一個標誌,並在mockMvc使用它的唯一的方式進行

mockMvc.perform(get("/resource") 
        .with(oAuthHelper.bearerToken("test")) 

而且OAuthHelper:

@Component 
@EnableAuthorizationServer 
public class OAuthHelper extends AuthorizationServerConfigurerAdapter { 

    @Autowired 
    AuthorizationServerTokenServices tokenservice; 

    @Autowired 
    ClientDetailsService clientDetailsService; 

    public RequestPostProcessor bearerToken(final String clientid) { 
     return mockRequest -> { 
      OAuth2AccessToken token = createAccessToken(clientid); 
      mockRequest.addHeader("Authorization", "Bearer " + token.getValue()); 
      return mockRequest; 
     }; 
    } 

    OAuth2AccessToken createAccessToken(final String clientId) { 
     ClientDetails client = clientDetailsService.loadClientByClientId(clientId); 
     Collection<GrantedAuthority> authorities = client.getAuthorities(); 
     Set<String> resourceIds = client.getResourceIds(); 
     Set<String> scopes = client.getScope(); 

     Map<String, String> requestParameters = Collections.emptyMap(); 
     boolean approved = true; 
     String redirectUrl = null; 
     Set<String> responseTypes = Collections.emptySet(); 
     Map<String, Serializable> extensionProperties = Collections.emptyMap(); 

     OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, clientId, authorities, 
       approved, scopes, resourceIds, redirectUrl, responseTypes, extensionProperties); 

     User userPrincipal = new User("user", "", true, true, true, true, authorities); 
     UsernamePasswordAuthenticationToken authenticationToken = 
       new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities); 
     OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken); 

     return tokenservice.createAccessToken(auth); 
    } 

    @Override 
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { 
     clients.inMemory() 
       .withClient("test") 
       .authorities("READ"); 
    } 

} 
+1

問題是我在生產中創建令牌的安全服務是使用令牌來檢查授權和驗證的服務的另一個微服務......並且由於它的JWT令牌使用私鑰文件來創建該令牌,我不希望有私人令牌擴展所有我的資源微服務。或者我有什麼問題? – David

+0

是的,我有相同的設計,所以要測試暴露資源的微服務,我在測試中做到了這一點 –

+0

我也有一個在驗證服務privete密鑰和其他微服務 –

相關問題