我有两个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错误。
1条答案
按热度按时间vhmi4jdf1#
经过一番调查,我找到了自己问题的解决方案,当使用Spring Security允许在没有身份验证或授权的情况下访问所有请求时,我最初使用了以下配置:
然而,这并没有像预期的那样工作,我在向我的Sping Boot 应用程序发出请求时仍然收到401未经授权的错误。
然后,我尝试使用以下配置:
这正如预期的那样工作,允许访问所有请求而无需身份验证或授权。
我不知道为什么使用requestMatchers(“*”)在我的情况下不起作用,但使用anyRequest()似乎解决了这个问题。
我希望这对其他面临类似问题的人有所帮助。