Spring Security 5.1 - 使用 WebClient 获取客户端凭据流的令牌 [英] Spring Security 5.1 - Get Token for Client Credentials Flow with WebClient

查看:51
本文介绍了Spring Security 5.1 - 使用 WebClient 获取客户端凭据流的令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过 webclient 获取不记名令牌,并使用以下设置对 servlet 应用程序中的安全资源服务器进行集成测试.

I am attempting to get a bearer token via a webclient with the following setup for an integration test of a secured resource server in a servlet application.

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();
    }

并将网络客户端自动连接到测试并像这样调用它,

and autowiring the webclient to a test and calling it like so,

webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("idp")).retrieve()
                .bodyToMono(String.class).block();

我假设交换功能要么获取访问令牌(如果可用),要么调用从 IDP 获取新令牌.但是它总是会失败,因为 HttpSessionOAuth2AuthorizedClientRepository 因为 HttpServletRequest 为空.

It is my assumption the exchange function would either get an access token if available, or do a call to get a new one from the IDP. However it will always fail as the HttpSessionOAuth2AuthorizedClientRepository as the HttpServletRequest is null.

整体测试看起来像这样,这会进入自动配置,为 IDP 提供程序配置一些 bean.

With the overall test looking like, this feeds into an autoconfiguration to configure some beans for an IDP provider.

@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 客户端实现的文档.

Is there anyway for a webclient to get the token for me and add it to the request? I know this was possible with the spring-security-oauth:OAuthRestTemplate and reading the documentation I thought it was possible with a web client.

推荐答案

这里的问题是您没有以正确的方式实例化 WebClient.

The problem here is that you are not instancing your WebClient the right way.

由于您在客户端,您无权访问 OAuth2AuthorizedClientRepository.该 bean 应该链接到您使用 HttpSecurity 配置中的 .oauth2Login() 方法声明登录的资源服务器.这些详细信息在此处解释:Spring Security 5 Oauth2 登录.

As you are on the client side, you do not have access to an OAuth2AuthorizedClientRepository. This bean is supposed to be linked to a resource sever on which you log into using the .oauth2Login() method declaration on the HttpSecurityconfiguration. These details are explained here : Spring Security 5 Oauth2 Login.

同样,您在客户端,因此您需要一个交换过滤器功能,该功能将触发对授权服务器的请求以获取 JWT 令牌.您可以改用 ServerOAuth2AuthorizedClientExchangeFilterFunction.

Again, you are on the client side so what you need is an exchange filter function which will trigger a request to an authorization server to get a JWT token. You can use the ServerOAuth2AuthorizedClientExchangeFilterFunction instead.

最好使用WebClientCustomizer在WebClient过滤器中添加交换过滤器功能.为什么?仅仅因为在您的 Spring 应用程序中注入一个 WebClient.Builder 将允许您访问链接到网络交换的本机指标.

You better use a WebClientCustomizer to add the exchange filter function in the WebClient filter. Why ? Simply because injecting in your Spring application a WebClient.Builder will allow you accessing native metrics linked to web exchanges.

因此,您将使用 UnAuthenticatedServerOAuth2AuthorizedClientRepository bean 的新实例构建您的 WebClient,如下所示:

Hence, you will build your WebClient using a new instance of an UnAuthenticatedServerOAuth2AuthorizedClientRepository bean like this :

// 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 安全文档:类 UnAuthenticatedServerOAuth2AuthorizedClientRepository.

As you are on the client side, you are not associating a user to your process, that's why you can not use any authorized client repository bean instanciation. Check on Spring Security documentation : Spring Security documentation : Class UnAuthenticatedServerOAuth2AuthorizedClientRepository.

我尝试在以下 GitHub 项目中总结一个演示案例:GitHub - Spring SecurityOAuth2 机器对机器场景.

I tried to sum up a demo case in the following GitHub project : GitHub - Spring Security OAuth2 Machine-To-Machine scenario.

我希望这能让您更深入地了解 WebClient 配置.如果您有任何问题,请询问.

I hope this gives you more insights on WebClient configuration. Please ask if you have any question.

这篇关于Spring Security 5.1 - 使用 WebClient 获取客户端凭据流的令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆