我正在尝试通过webclient以下设置获取承载令牌,以对Servlet应用程序中的受保护资源服务器进行集成测试。
webclient
spring: security: oauth2: client: registration: idp: clientId: id clientSecret: secret authorization-grant-type: client_credentials scope: read provider: idp: authorization-uri: myidp/authorization.oauth2 token-uri: myidp/token.oauth2 user-info-uri: myidp/userinfo.openid user-name-attribute: name
还有豆子
@Bean WebClient webClient(ClientRegistrationRepository clientRegistrations, OAuth2AuthorizedClientRepository authorizedClients) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction( clientRegistrations, authorizedClients); // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly // oauth.setDefaultOAuth2AuthorizedClient(true); // (optional) set a default ClientRegistration.registrationId // oauth.setDefaultClientRegistrationId("client-registration-id"); return WebClient.builder().apply(oauth.oauth2Configuration()).build(); }
并自动将Web客户端连接到测试,然后像这样调用它,
webClient.get().uri("http://localhost:" + port + "/web/it") .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("idp")).retrieve() .bodyToMono(String.class).block();
我假设交换功能将获取访问令牌(如果可用),或者进行调用以从IDP获取新令牌。但是,它将始终失败,HttpSessionOAuth2AuthorizedClientRepository因为the HttpServletRequest为null。
HttpSessionOAuth2AuthorizedClientRepository
HttpServletRequest
在总体测试看起来像这样的情况下,它可以自动配置为IDP提供程序配置一些bean。
@SpringBootTest(classes = WebITApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ExtendWith(SpringExtension.class) @ActiveProfiles("web-it") class WebJwtIt { @LocalServerPort private int port; @Autowired private WebClient webClient; @Test void testIdpJwt() { String response = webClient.get().uri("http://localhost:" + port + "/web/it") .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("ping")).retrieve() .bodyToMono(String.class).block(); assertThat(response).isEqualTo("pass"); } @RestController @SpringBootApplication @ImportAutoConfiguration(IdpAutoConfiguration.class) static class WebITApplication implements IdpSecurityAdapter { @Bean WebClient webClient(ClientRegistrationRepository clientRegistrations, OAuth2AuthorizedClientRepository authorizedClients) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction( clientRegistrations, authorizedClients); // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly // oauth.setDefaultOAuth2AuthorizedClient(true); // (optional) set a default ClientRegistration.registrationId // oauth.setDefaultClientRegistrationId("client-registration-id"); return WebClient.builder().apply(oauth.oauth2Configuration()).build(); } public static void main(String args[]) { new SpringApplicationBuilder().profiles("web-it").build().run(WebITApplication.class, args); } @GetMapping public String secured() { return "secured"; } @GetMapping("/web/it") public String securedOne() { return "pass"; } @Override public void configure(final HttpSecurity httpSecurity) throws IdpSecurityAdapterException { try { httpSecurity.oauth2Client(); } catch (Exception e) { throw new IdpSecurityAdapterException("Failed to Configure Oauth2Client", e); } } @Override public IdpProvider getIdpProvider() { return IdpProvider.MyIdp; } }
无论如何,网络客户端是否可以为我获取令牌并将其添加到请求中?我知道这是可能的,spring-security- oauth:OAuthRestTemplate并且阅读我认为可以通过Web客户端实现的文档。
spring-security- oauth:OAuthRestTemplate
这里的问题是您没有以正确的方式实例化WebClient。
由于您位于 客户端 ,因此您无权访问OAuth2AuthorizedClientRepository。该bean应该链接到您使用配置.oauth2Login()上的方法声明登录到的资源服务器HttpSecurity。这些细节在这里解释:Spring Security 5 Oauth2登录。
OAuth2AuthorizedClientRepository
.oauth2Login()
HttpSecurity
同样,您在 客户端, 因此需要一个交换筛选器功能,该功能将触发向授权服务器的请求以获取JWT令牌。您可以使用ServerOAuth2AuthorizedClientExchangeFilterFunction代替。
ServerOAuth2AuthorizedClientExchangeFilterFunction
最好使用a WebClientCustomizer在WebClient过滤器中添加交换过滤器功能。为什么呢 仅仅因为在Spring应用程序中注入a WebClient.Builder将使您能够访问链接到Web交换的本机指标。
WebClientCustomizer
WebClient.Builder
因此,您将使用UnAuthenticatedServerOAuth2AuthorizedClientRepository如下所示的bean 的新实例来构建WebClient :
UnAuthenticatedServerOAuth2AuthorizedClientRepository
// Use injection to get an in-memory reposiroty or client registrations @Bean WebClient webClient(ClientRegistrationRepository clientRegistrations) { // Provides support for an unauthenticated user such as an application ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction( clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository()); // Build up a new WebClientCustomizer implementation to inject the oauth filter // function into the WebClient.Builder instance return new WebClientSecurityCustomizer(oauth); }
正如您在 客户端上一样 ,您没有将用户与您的流程相关联,这就是为什么您不能使用任何授权的客户端存储库bean实例化的原因。查看Spring Security文档:Spring Security文档:UnAuthenticatedServerOAuth2AuthorizedClientRepository类。
我试图在以下GitHub项目中总结一个演示案例:GitHub-Spring Security OAuth2 Machine-To- Machine场景。
我希望这能为您提供有关WebClient配置的更多见解。请问您有什么问题。