我有两个 Spring Boot 服务,S1 和 S2,它们都有自己的 API 端点。 S1 受 OAuth2 客户端凭据保护,因此我已将 S2 配置为 OAuth2 客户端,并使用
WebClient
在 S2 上发出 API 请求。为此,我向我的 S2 应用程序添加了两个依赖项
spring-boot-starter-oauth2-client
和spring-boot-starter-webflux
.WebClient
和我的application.properties
文件的配置如下:
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 授权,同时允许拨入电话绕过此要求的建议。我正在使用 Spring 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 调用。添加此内容后,我现在收到禁止错误。
经过一番调查,我找到了自己问题的解决方案。 在使用 Spring Security 允许访问所有无需认证或授权的请求时,我最初使用了以下配置:
http
.csrf().disable()
.authorizeRequests()
.requestMatchers("*").permitAll()
.and()
.build();
但是,这并没有按预期工作,在向我的 Spring Boot 应用程序发出请求时,我仍然收到 401 Unauthorized 错误。
然后我尝试使用以下配置:
http
.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll()
.and()
.build();
这按预期工作,允许访问所有请求而无需身份验证或授权。
我不确定为什么在我的情况下使用
requestMatchers("*")
不起作用,但使用 anyRequest()
似乎解决了这个问题。
我希望这可以帮助其他面临类似问题的人。