spring 如何在Sping Boot 微服务中使用OAuth2授权保护传出API调用,同时保持传入API调用不受保护?

w46czmvw  于 2023-03-16  发布在  Spring
关注(0)|答案(1)|浏览(186)

我有两个Sping Boot 服务S1和S2,它们都有自己的API端点。S1使用OAuth2客户端凭据进行保护,因此我将S2配置为OAuth2客户端,并使用WebClient在S2上发出API请求。为此,我向S2应用程序添加了两个依赖项
1.Spring引导启动器oauth2客户端和
1.Spring启动器webflux。
WebClient和我的应用程序属性文件的配置如下:

spring:
  security:
    oauth2:
      client:
        registration:
          liferayclient:
            client-id: ${CLIENT_ID:bcvc7yt7}
            client-secret: ${CLIENT_SECRET:vhsvchc76}
            authorization-grant-type: client_credentials
        provider:
          liferayclient:
            token-uri: localhost:8080/o/oauth2/token

WebClient配置为:

@Configuration
public class WebClientConfig {

    @Bean
    WebClient webClient(AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
        ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
                .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
                .build();

        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        oauth2Client.setDefaultClientRegistrationId("liferayclient");
        HttpClient httpClient = HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10 * 1000)
                .doOnConnected(connection -> {
                    connection.addHandlerLast(new ReadTimeoutHandler(2 * 60 * 1000L, MILLISECONDS));
                    connection.addHandlerLast(new WriteTimeoutHandler(2 * 60 * 1000L, MILLISECONDS));
                });

        return WebClient.builder()
                .filter(oauth2Client)
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .exchangeStrategies(exchangeStrategies)
                .build();
    }

    @Bean
    ReactiveClientRegistrationRepository clientRegistrations(
            @Value("${spring.security.oauth2.client.provider.liferayclient.token-uri}") String token_uri,
            @Value("${spring.security.oauth2.client.registration.liferayclient.client-id}") String client_id,
            @Value("${spring.security.oauth2.client.registration.liferayclient.client-secret}") String client_secret,
            @Value("${spring.security.oauth2.client.registration.liferayclient.authorization-grant-type}") String authorizationGrantType

    ) {
        ClientRegistration registration = ClientRegistration
                .withRegistrationId("liferayclient")
                .tokenUri(token_uri)
                .clientId(client_id)
                .clientSecret(client_secret)
                .authorizationGrantType(new AuthorizationGrantType(authorizationGrantType))
                .build();
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }

    @Bean
    public AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository) {

        InMemoryReactiveOAuth2AuthorizedClientService clientService =
                new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);

        ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build();

        AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, clientService);

        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
}

现在,我可以使用Web客户端从S2成功调用S1上的API。但是,我遇到了无法调用服务S2上的任何API的问题。每当我尝试在S2上调用API时,Web浏览器上都会出现“使用OAuth 2.0登录”提示。我得到的html响应如下所示。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Please sign in</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"
        crossorigin="anonymous" />
</head>

<body>
    <div class="container">
        <h2 class="form-signin-heading">Login with OAuth 2.0</h2>
        <table class="table table-striped">
        </table>
    </div>
</body>

</html>

在添加spring-boot-starter-oauth2-client依赖项之前,我可以使用POSTMAN进行这些API调用,没有任何问题。似乎自从添加了依赖项后,Spring现在希望当前微服务也受OAuth2保护。因此,在当前微服务中创建的任何REST API都将自动受OAuth2保护。
我正在寻求有关如何解决这个问题的建议,并使传出呼叫需要OAuth2授权,同时允许传入呼叫绕过这一要求。我正在使用Sping Boot 版本3.0.0,我已经尝试了以下解决方案之一。

package com.report.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig{
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
        return http.csrf().disable().authorizeHttpRequests().requestMatchers("*").permitAll().and().build();
    }
}

我尝试创建一个允许所有HTTP请求的自定义SecurityFilterChain bean,但它没有帮助我。虽然我可以像以前一样使用WebClient从S2向S1进行API调用,但我仍然无法通过Postman在S2上进行任何API调用。添加此错误后,我现在收到一个Forbidden错误。

vhmi4jdf

vhmi4jdf1#

经过一番调查,我找到了自己问题的解决方案,当使用Spring Security允许在没有身份验证或授权的情况下访问所有请求时,我最初使用了以下配置:

http.csrf().disable().authorizeRequests().requestMatchers("*").permitAll().and().build();

然而,这并没有像预期的那样工作,我在向我的Sping Boot 应用程序发出请求时仍然收到401未经授权的错误。
然后,我尝试使用以下配置:

http.csrf().disable().authorizeRequests().anyRequest().permitAll().and().build();

这正如预期的那样工作,允许访问所有请求而无需身份验证或授权。
我不知道为什么使用requestMatchers(“*”)在我的情况下不起作用,但使用anyRequest()似乎解决了这个问题。
我希望这对其他面临类似问题的人有所帮助。

相关问题