2015-04-08 126 views
28

繼Spring Security 4發佈之後,我想更新當前的Spring安全性oauth2資源服務器測試。如何測試spring-security-oauth2資源服務器的安全性?

目前我有一個輔助類,使用ResourceOwnerPasswordResourceDetails與連接到實際AccessTokenUri來請求我的測試有效令牌測試ClientId建立了一個OAuth2RestTemplate。這個模板然後用於在我的@WebIntegrationTest中發出請求。

我想砸實際AuthorizationServer的依賴,並使用有效(如果限制)在我的測試用戶憑據,在春季安全採取新的測試支持的優勢4.

最多到現在爲止,我所有嘗試使用@WithMockUser,@WithSecurityContext,SecurityMockMvcConfigurers.springSecurity() & SecurityMockMvcRequestPostProcessors.*未能通過MockMvc進行身份驗證的調用,並且我在Spring示例項目中找不到任何這樣的工作示例。

任何人都可以幫助我測試我的oauth2資源服務器與某種嘲笑的憑據,同時仍然測試施加的安全限制嗎?

** 編輯 ** 示例代碼可在這裏:https://github.com/timtebeek/resource-server-testing 對於每個測試類我明白爲什麼它不會因爲它的工作,但我正在尋找辦法,讓我來測試安全設置很容易。

我現在正在考慮在src/test/java下創建一個非常寬鬆的OAuthServer,這可能會有所幫助。有沒有人有任何其他建議?

+0

你能提供一個你的測試是什麼樣子的例子嗎?你只是測試基於安全性的方法嗎?你在使用MockMvc嗎?您是否將實際的REST呼叫轉到您的服務? –

+0

@RobWinch我已經使用每種方法添加了示例代碼,並理解它爲什麼不起作用。我正在尋找可以在測試安全性方面工作的方法。 – Tim

+0

謝謝你,所有的代碼。 運行testHelloUser#MyControllerIT.java時,我似乎得到了401。 你能幫我解決這個問題嗎? – myspri

回答

29

爲了有效地測試資源服務器的安全性,都與MockMvcRestTemplate它有助於配置AuthorizationServersrc/test/java

AuthorizationServer

@Configuration 
@EnableAuthorizationServer 
@SuppressWarnings("static-method") 
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 
    @Bean 
    public JwtAccessTokenConverter accessTokenConverter() throws Exception { 
     JwtAccessTokenConverter jwt = new JwtAccessTokenConverter(); 
     jwt.setSigningKey(SecurityConfig.key("rsa")); 
     jwt.setVerifierKey(SecurityConfig.key("rsa.pub")); 
     jwt.afterPropertiesSet(); 
     return jwt; 
    } 

    @Autowired 
    private AuthenticationManager authenticationManager; 

    @Override 
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
     endpoints 
     .authenticationManager(authenticationManager) 
     .accessTokenConverter(accessTokenConverter()); 
    } 

    @Override 
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { 
     clients.inMemory() 
     .withClient("myclientwith") 
     .authorizedGrantTypes("password") 
     .authorities("myauthorities") 
     .resourceIds("myresource") 
     .scopes("myscope") 

     .and() 
     .withClient("myclientwithout") 
     .authorizedGrantTypes("password") 
     .authorities("myauthorities") 
     .resourceIds("myresource") 
     .scopes(UUID.randomUUID().toString()); 
    } 
} 

集成測試
對於集成測試一個然後可以簡單地使用內置的OAuth2測試支持規則和註釋:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = MyApp.class) 
@WebIntegrationTest(randomPort = true) 
@OAuth2ContextConfiguration(MyDetails.class) 
public class MyControllerIT implements RestTemplateHolder { 
    @Value("http://localhost:${local.server.port}") 
    @Getter 
    String      host; 

    @Getter 
    @Setter 
    RestOperations    restTemplate = new TestRestTemplate(); 

    @Rule 
    public OAuth2ContextSetup context   = OAuth2ContextSetup.standard(this); 

    @Test 
    public void testHelloOAuth2WithRole() { 
     ResponseEntity<String> entity = getRestTemplate().getForEntity(host + "/hello", String.class); 
     assertTrue(entity.getStatusCode().is2xxSuccessful()); 
    } 
} 

class MyDetails extends ResourceOwnerPasswordResourceDetails { 
    public MyDetails(final Object obj) { 
     MyControllerIT it = (MyControllerIT) obj; 
     setAccessTokenUri(it.getHost() + "/oauth/token"); 
     setClientId("myclientwith"); 
     setUsername("user"); 
     setPassword("password"); 
    } 
} 

MockMvc測試
測試與MockMvc也是可能的,但需要一點輔助類來獲得一個RequestPostProcessor,設置在請求Authorization: Bearer <token>頭:

@Component 
public class OAuthHelper { 
    // For use with MockMvc 
    public RequestPostProcessor bearerToken(final String clientid) { 
     return mockRequest -> { 
      OAuth2AccessToken token = createAccessToken(clientid); 
      mockRequest.addHeader("Authorization", "Bearer " + token.getValue()); 
      return mockRequest; 
     }; 
    } 

    @Autowired 
    ClientDetailsService    clientDetailsService; 
    @Autowired 
    AuthorizationServerTokenServices tokenservice; 

    OAuth2AccessToken createAccessToken(final String clientId) { 
     // Look up authorities, resourceIds and scopes based on clientId 
     ClientDetails client = clientDetailsService.loadClientByClientId(clientId); 
     Collection<GrantedAuthority> authorities = client.getAuthorities(); 
     Set<String> resourceIds = client.getResourceIds(); 
     Set<String> scopes = client.getScope(); 

     // Default values for other parameters 
     Map<String, String> requestParameters = Collections.emptyMap(); 
     boolean approved = true; 
     String redirectUrl = null; 
     Set<String> responseTypes = Collections.emptySet(); 
     Map<String, Serializable> extensionProperties = Collections.emptyMap(); 

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

     // Create OAuth2AccessToken 
     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); 
    } 
} 

MockMvc測試必須再從OauthHelper類獲得RequestPostProcessor,並在發出請求時傳遞它:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = MyApp.class) 
@WebAppConfiguration 
public class MyControllerTest { 
    @Autowired 
    private WebApplicationContext webapp; 

    private MockMvc     mvc; 

    @Before 
    public void before() { 
     mvc = MockMvcBuilders.webAppContextSetup(webapp) 
       .apply(springSecurity()) 
       .alwaysDo(print()) 
       .build(); 
    } 

    @Autowired 
    private OAuthHelper helper; 

    @Test 
    public void testHelloWithRole() throws Exception { 
     RequestPostProcessor bearerToken = helper.bearerToken("myclientwith"); 
     mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isOk()); 
    } 

    @Test 
    public void testHelloWithoutRole() throws Exception { 
     RequestPostProcessor bearerToken = helper.bearerToken("myclientwithout"); 
     mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isForbidden()); 
    } 
} 

一個完整的示例項目可在GitHub上:
https://github.com/timtebeek/resource-server-testing

+0

使用TestingAuthenticationToken(github示例)和UsernamePasswordAuthenticationToken(示例張貼在這裏)之間有什麼區別?看起來代碼可以與認證接口的任何實現一起工作......我錯過了什麼? – treaz

+0

猜你說的是我以前在GitHub上使用'TestingAuthenticationToken':沒有必要使用'UsernamePasswordAuthenticationToken';這只是我從「ClientDetailsS​​ervice」提取細節值所做的更改的一部分。你會很好地使用以前的版本,但我從現在開始使用它。 – Tim

+0

這工作正常,但UsernamePasswordAuthenticationToken authenticationToken中的權限應該是用戶的權限,而不是客戶端的權限。 – alex

4

好的,我還沒有能夠使用新的@WithMockUser或相關注釋來測試我的獨立oauth2 JWT令牌受保護的資源服務器。

作爲解決方法,我可以通過設置a permissive AuthorizationServer under src/test/java來集成測試資源服務器安全性,並定義了兩個使用我使用的客戶端through a helper class。這讓我有一些方式,但它還不是我想測試各種用戶,角色,示波器等的容易。

我從這裏猜測它應該更容易實現我自己的WithSecurityContextFactory創建一個OAuth2Authentication,而不是通常的UsernamePasswordAuthentication。但是,我還沒有弄清楚如何輕鬆設置這些細節。歡迎任何意見或建議如何設置。

16

我發現了一個更簡單的方法來做到這一點下面的方向我在這裏讀到:http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test-method-withsecuritycontext。此解決方案特定於使用#oauth2.hasScope測試@PreAuthorize,但我相信它也可以適用於其他情況。

創建其中可以應用到@Test秒的註解:使用MockMvc

WithMockOAuth2Scope

import org.springframework.security.test.context.support.WithSecurityContext; 

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Retention(RetentionPolicy.RUNTIME) 
@WithSecurityContext(factory = WithMockOAuth2ScopeSecurityContextFactory.class) 
public @interface WithMockOAuth2Scope { 

    String scope() default ""; 
} 

WithMockOAuth2ScopeSecurityContextFactory

import org.springframework.security.core.Authentication; 
import org.springframework.security.core.context.SecurityContext; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.oauth2.provider.OAuth2Authentication; 
import org.springframework.security.oauth2.provider.OAuth2Request; 
import org.springframework.security.test.context.support.WithSecurityContextFactory; 

import java.util.HashSet; 
import java.util.Set; 

public class WithMockOAuth2ScopeSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuth2Scope> { 

    @Override 
    public SecurityContext createSecurityContext(WithMockOAuth2Scope mockOAuth2Scope) { 
     SecurityContext context = SecurityContextHolder.createEmptyContext(); 

     Set<String> scope = new HashSet<>(); 
     scope.add(mockOAuth2Scope.scope()); 

     OAuth2Request request = new OAuth2Request(null, null, null, true, scope, null, null, null, null); 

     Authentication auth = new OAuth2Authentication(request, null); 

     context.setAuthentication(auth); 

     return context; 
    } 
} 

實施例試驗:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringBootTest 
public class LoadScheduleControllerTest { 

    private MockMvc mockMvc; 

    @Autowired 
    LoadScheduleController loadScheduleController; 

    @Before 
    public void setup() { 
     mockMvc = MockMvcBuilders.standaloneSetup(loadScheduleController) 
        .build(); 
    } 

    @Test 
    @WithMockOAuth2Scope(scope = "dataLicense") 
    public void testSchedule() throws Exception { 
     mockMvc.perform(post("/schedule").contentType(MediaType.APPLICATION_JSON_UTF8).content(json)).andDo(print()); 
    } 
} 

這是測試控制器:

@RequestMapping(value = "/schedule", method = RequestMethod.POST) 
@PreAuthorize("#oauth2.hasScope('dataLicense')") 
public int schedule() { 
    return 0; 
} 
+0

有趣的方法!可能使我不必設置授權服務器並獲取測試令牌。我無法在「OAuth2Authentication」中調整您的示例以使用特定用戶。雖然我的安全模型主要基於您是誰,而不是您的令牌的範圍。有關如何調整您的樣本以支持這些建議的任何建議? – Tim

+1

@Tim您應該可以將安全上下文中的Authentication設置爲任意的Authentication對象。我認爲這裏的主要區別可能是您嘗試使用真正的「OAuth2RestTemplate」發送請求,而我在測試中正在使用mockMvc發送請求。 – mclaassen

+0

謝謝!終於可以更清楚地看到這一點,並相應地更新了我的示例項目:https://github.com/timtebeek/resource-server-testing/pull/1 這兩種方法現在都可以使用,但是可以用於不同的目的。對於基於用戶名/範圍的訪問規則,我會推薦你​​的方法;在我的情況下,我解碼訪問令牌並根據其中的屬性制定多租戶訪問規則;這真的需要一個實際的令牌。 :) – Tim

5

春季啓動1.5引入了test slices@WebMvcTest。使用這些測試片並手動加載OAuth2AutoConfiguration會使您的測試更少的樣板化,並且它們的運行速度會比建議的基於@SpringBootTest的解決方案更快。如果您還導入生產安全配置,則可以測試配置的過濾器鏈是否適用於您的Web服務。

這裏有一些額外的課程,你可能會發現有益沿着設置:

控制器

@RestController 
@RequestMapping(BookingController.API_URL) 
public class BookingController { 

    public static final String API_URL = "/v1/booking"; 

    @Autowired 
    private BookingRepository bookingRepository; 

    @PreAuthorize("#oauth2.hasScope('myapi:write')") 
    @PatchMapping(consumes = APPLICATION_JSON_UTF8_VALUE, produces = APPLICATION_JSON_UTF8_VALUE) 
    public Booking patchBooking(OAuth2Authentication authentication, @RequestBody @Valid Booking booking) { 
     String subjectId = MyOAuth2Helper.subjectId(authentication); 
     booking.setSubjectId(subjectId); 
     return bookingRepository.save(booking); 
    } 
} 

測試

@RunWith(SpringRunner.class) 
@AutoConfigureJsonTesters 
@WebMvcTest 
@Import(DefaultTestConfiguration.class) 
public class BookingControllerTest { 

    @Autowired 
    private MockMvc mvc; 

    @Autowired 
    private JacksonTester<Booking> json; 

    @MockBean 
    private BookingRepository bookingRepository; 

    @MockBean 
    public ResourceServerTokenServices resourceServerTokenServices; 

    @Before 
    public void setUp() throws Exception { 
     // Stub the remote call that loads the authentication object 
     when(resourceServerTokenServices.loadAuthentication(anyString())).thenAnswer(invocation -> SecurityContextHolder.getContext().getAuthentication()); 
    } 

    @Test 
    @WithOAuthSubject(scopes = {"myapi:read", "myapi:write"}) 
    public void mustHaveValidBookingForPatch() throws Exception { 
     mvc.perform(patch(API_URL) 
      .header(AUTHORIZATION, "Bearer foo") 
      .content(json.write(new Booking("myguid", "aes")).getJson()) 
      .contentType(MediaType.APPLICATION_JSON_UTF8) 
     ).andExpect(status().is2xxSuccessful()); 
    } 
} 

DefaultTestConfiguration

@TestConfiguration 
@Import({MySecurityConfig.class, OAuth2AutoConfiguration.class}) 
public class DefaultTestConfiguration { 

} 

MySecurityConfig(這是用於生產):

@Configuration 
@EnableOAuth2Client 
@EnableResourceServer 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
      .antMatchers("/v1/**").authenticated(); 
    } 

} 

自定義註釋從測試注射範圍:

@Target({ElementType.TYPE, ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME) 
@WithSecurityContext(factory = WithOAuthSubjectSecurityContextFactory.class) 
public @interface WithOAuthSubject { 

    String[] scopes() default {"myapi:write", "myapi:read"}; 

    String subjectId() default "a1de7cc9-1b3a-4ecd-96fa-dab6059ccf6f"; 

} 

工廠類處理自定義註解

public class WithOAuthSubjectSecurityContextFactory implements WithSecurityContextFactory<WithOAuthSubject> { 

    private DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter(); 

    @Override 
    public SecurityContext createSecurityContext(WithOAuthSubject withOAuthSubject) { 
     SecurityContext context = SecurityContextHolder.createEmptyContext(); 

     // Copy of response from https://myidentityserver.com/identity/connect/accesstokenvalidation 
     Map<String, ?> remoteToken = ImmutableMap.<String, Object>builder() 
      .put("iss", "https://myfakeidentity.example.com/identity") 
      .put("aud", "oauth2-resource") 
      .put("exp", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "") 
      .put("nbf", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "") 
      .put("client_id", "my-client-id") 
      .put("scope", Arrays.asList(withOAuthSubject.scopes())) 
      .put("sub", withOAuthSubject.subjectId()) 
      .put("auth_time", OffsetDateTime.now().toEpochSecond() + "") 
      .put("idp", "idsrv") 
      .put("amr", "password") 
      .build(); 

     OAuth2Authentication authentication = defaultAccessTokenConverter.extractAuthentication(remoteToken); 
     context.setAuthentication(authentication); 
     return context; 
    } 
} 

我使用我們的身份服務器的響應副本創建一個現實的OAuth2Authentication。你大概可以複製我的代碼。如果您想重複身份服務器的過程,請在org.springframework.security.oauth2.provider.token.RemoteTokenServices#loadAuthenticationorg.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices#extractAuthentication中放置一個斷點,具體取決於您是否配置了自定義ResourceServerTokenServices或不是。

+0

來獲取你應用中的token值。哇,謝謝你付出努力想出一個這是一種全新的測試方法,正如您所說的那樣,速度可能更快,並且不會在應用程序上下文中設置不必要的部分。很酷! :) – Tim

+0

我曾嘗試過您的解決方案,但忘記在構建測試請求時添加Authentication標頭,並且無法正常工作:/。也許可以稍微強調必須將這個授權頭添加到涉及安全性的每個請求中? – ch4mp

1

我認爲有一種更清潔和更有意義的替代方法。

該方法是自動裝載令牌存儲,然後添加一個測試令牌,然後由其餘客戶端使用。

一個例子測試

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 
public class UserControllerIT { 

    @Autowired 
    private TestRestTemplate testRestTemplate; 

    @Autowired 
    private TokenStore tokenStore; 

    @Before 
    public void setUp() { 

     final OAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO"); 
     final ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_CLIENT"); 
     final OAuth2Authentication authentication = new OAuth2Authentication(
       new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), null); 

     tokenStore.storeAccessToken(token, authentication); 

    } 

    @Test 
    public void testGivenPathUsersWhenGettingForEntityThenStatusCodeIsOk() { 

     final HttpHeaders headers = new HttpHeaders(); 
     headers.add(HttpHeaders.AUTHORIZATION, "Bearer FOO"); 
     headers.setContentType(MediaType.APPLICATION_JSON); 

     // Given Path Users 
     final UriComponentsBuilder uri = UriComponentsBuilder.fromPath("/api/users"); 

     // When Getting For Entity 
     final ResponseEntity<String> response = testRestTemplate.exchange(uri.build().toUri(), HttpMethod.GET, 
       new HttpEntity<>(headers), String.class); 

     // Then Status Code Is Ok 
     assertThat(response.getStatusCode(), is(HttpStatus.OK)); 
    } 

} 

我個人認爲,這是不恰當的單元測試與自啓用安全性的安全性的控制器是一個單獨的層到控制器。我會創建一個測試所有層的集成測試。但是,上述方法可以很容易地修改,以創建一個使用MockMvc的單元測試。

上述代碼的靈感來自Dave Syer編寫的Spring Security test

請注意,此方法適用於與授權服務器共享相同令牌存儲的資源服務器。如果您的資源服務器與授權服務器不共享相同的令牌存儲,我建議使用using wiremock to mock the http responses

2

我對此有另一種解決方案。見下文。

@RunWith(SpringRunner.class) 
@SpringBootTest 
@WebAppConfiguration 
@ActiveProfiles("test") 
public class AccountContollerTest { 

    public static Logger log = LoggerFactory.getLogger(AccountContollerTest.class); 


    @Autowired 
    private WebApplicationContext webApplicationContext; 

    private MockMvc mvc; 

    @Autowired 
    FilterChainProxy springSecurityFilterChain; 

    @Autowired 
    UserRepository users; 

    @Autowired 
    PasswordEncoder passwordEncoder; 

    @Autowired 
    CustomClientDetailsService clientDetialsService; 

    @Before 
    public void setUp() { 
     mvc = MockMvcBuilders 
       .webAppContextSetup(webApplicationContext) 
       .apply(springSecurity(springSecurityFilterChain)) 
       .build(); 

     BaseClientDetails testClient = new ClientBuilder("testclient") 
        .secret("testclientsecret") 
        .authorizedGrantTypes("password") 
        .scopes("read", "wirte") 
        .autoApprove(true) 
        .build(); 

     clientDetialsService.addClient(testClient); 

     User user = createDefaultUser("testuser", passwordEncoder.encode("testpassword"), "max", "Mustermann", new Email("[email protected]")); 

     users.deleteAll(); 
     users.save(user); 

    } 

    @Test 
    public void shouldRetriveAccountDetailsWithValidAccessToken() throws Exception { 
     mvc.perform(get("/api/me") 
       .header("Authorization", "Bearer " + validAccessToken()) 
       .accept(MediaType.APPLICATION_JSON)) 
       .andExpect(status().isOk()) 
       .andDo(print()) 
       .andExpect(jsonPath("$.userAuthentication.name").value("testuser")) 
       .andExpect(jsonPath("$.authorities[0].authority").value("ROLE_USER")); 
    } 

    @Test 
    public void shouldReciveHTTPStatusUnauthenticatedWithoutAuthorizationHeader() throws Exception{ 
     mvc.perform(get("/api/me") 
       .accept(MediaType.APPLICATION_JSON)) 
       .andDo(print()) 
       .andExpect(status().isUnauthorized()); 
    } 

    private String validAccessToken() throws Exception { 
     String username = "testuser"; 
     String password = "testpassword"; 

     MockHttpServletResponse response = mvc 
      .perform(post("/oauth/token") 
        .header("Authorization", "Basic " 
          + new String(Base64Utils.encode(("testclient:testclientsecret") 
          .getBytes()))) 
        .param("username", username) 
        .param("password", password) 
        .param("grant_type", "password")) 
      .andDo(print()) 
      .andReturn().getResponse(); 

    return new ObjectMapper() 
      .readValue(response.getContentAsByteArray(), OAuthToken.class) 
      .accessToken; 
    } 

    @JsonIgnoreProperties(ignoreUnknown = true) 
    private static class OAuthToken { 
     @JsonProperty("access_token") 
     public String accessToken; 
    } 
} 

希望它會幫助!

0

One more solution I tried to detail enough :-D

正是基於上述設置Authorization頭,像一些,但我想:

  • 不是創造實際有效JWT令牌和使用所有JWT認證堆棧(單位測試...)
  • 測試認證包含測試用例定義的範圍和權限

所以我:

  • 創建自定義批註與@WithSecurityContext和工廠,像其他一些沒有設立每個測試(在我的情況@WithJwtOAuth2Authentication
  • @MockBean的TokenStore返回與@WithJwt
  • 配置OAuth2Authentication
  • 提供MockHttpServletRequestBuilder工廠,該工廠設置由TokenStore模擬攔截的特定授權標頭以注入預期的認證。

P.S.

隨意接受/投我的解決辦法,如果它最符合您的需求;-)

+1

再次讀取所有堆棧,我只是意識到我的解決方案有多接近,[this one](https://stackoverflow.com/a/43676742/619830)是。我試過了,錯過了設置標題的那一行,並從頭開始構建了我自己的解決方案。最後,我只需再推一點OAuth2Authentication配置選項,並添加包裝程序,永遠不會忘記這個血腥頭文件。 – ch4mp

2

我發現與任何令牌存儲裝置測試春季安全資源服務器一個簡單而快速的方式。我的例子@EnabledResourceServer使用jwt令牌存儲。

這裏的魔術是我在集成測試中將JwtTokenStore替換爲InMemoryTokenStore

@RunWith (SpringRunner.class) 
@SpringBootTest (classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
@ActiveProfiles ("test") 
@TestPropertySource (locations = "classpath:application.yml") 
@Transactional 
public class ResourceServerIntegrationTest { 

@Autowired 
private TokenStore tokenStore; 

@Autowired 
private ObjectMapper jacksonObjectMapper; 

@LocalServerPort 
int port; 

@Configuration 
protected static class PrepareTokenStore { 

    @Bean 
    @Primary 
    public TokenStore tokenStore() { 
     return new InMemoryTokenStore(); 
    } 

} 

private OAuth2AccessToken token; 
private OAuth2Authentication authentication; 

@Before 
public void init() { 

    RestAssured.port = port; 

    token = new DefaultOAuth2AccessToken("FOO"); 
    ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_READER,ROLE_CLIENT"); 

    // Authorities 
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); 
    authorities.add(new SimpleGrantedAuthority("ROLE_READER")); 
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("writer", "writer", authorities); 

    authentication = new OAuth2Authentication(new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), authenticationToken); 
    tokenStore.storeAccessToken(token, authentication); 

} 

@Test 
public void gbsUserController_findById() throws Exception { 

    RestAssured.given().log().all().when().headers("Authorization", "Bearer FOO").get("/gbsusers/{id}", 2L).then().log().all().statusCode(HttpStatus.OK.value()); 

} 
相關問題