您好,我正在学习 Spring Security,并尝试根据 https://dzone.com/articles/implement-oauth-20-easily-with-spring-boot- 的指南创建一个简单的 OAuth2 客户端和资源服务器和-spr
我遇到了一个问题,编译器一直说找不到“ClientRegistrationRepository”的 bean。我在网上做了一些挖掘,它说如果 Spring 客户端配置配置正确,它应该可以工作。有类似问题的人说问题可能是由属性文件中的缩进问题引起的,但我没有看到这种情况。
请您帮忙看看是否有什么配置不正确的地方,谢谢。
控制台输出
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method webClient in com.somecompany.configuration.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' in your configuration.
OAuth2客户端主类
package com.somecompany;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Oauth2DemoClientApplication {
public static void main(String[] args) {
SpringApplication.run(Oauth2DemoClientApplication.class, args);
}
}
OAuth2 客户端控制器
package com.somecompany.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
@RequestMapping("/api/client")
public class Oauth2DemoClientController {
@Autowired
private WebClient webClient;
@Value("${resourceServer.url}")
private String resourceServerUrl;
@Value("${resourceServer.helloPath}")
private String resourceServerHelloPath;
@GetMapping("/")
public String home(@AuthenticationPrincipal OidcUser user) {
return "Welcome " + user.getFullName();
}
@GetMapping("/hello")
public String sayHello() {
return webClient.get().uri(resourceServerUrl + resourceServerHelloPath).retrieve().bodyToMono(String.class)
.block();
}
}
OAuth2 客户端配置
package com.somecompany.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Value("${defaultClientApplication}")
private String defaultClientApplication;
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrations,
OAuth2AuthorizedClientRepository authorizedClients) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations, authorizedClients);
oauth2.setDefaultOAuth2AuthorizedClient(true);
oauth2.setDefaultClientRegistrationId(defaultClientApplication);
return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
}
}
OAuth2 客户端应用程序.yml
logging.level.root: "debug"
defaultClientApplication: "okta"
spring:
security:
oauth2:
client:
provider:
okta:
issuer-uri: "https://dev-27548664.okta.com/oauth2/default"
registration:
okta:
client-id: {client ID}
client-secret: {client secret}
resourceServer:
url: "http://localhost:8081"
helloPath: "/api/resource/hello"
OAuth2 客户端 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.somecompany</groupId>
<artifactId>oauth2-demo-client</artifactId>
<version>1.0.0</version>
<name>oauth2-demo-client</name>
<description>oauth2-demo-client</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
问题在于您的
application.yml
配置缩进。 security
应该是 spring
的孩子:
spring:
security:
oauth2:
更新:
YML 属性区分大小写。尝试将
resourceServer
更改为 resourceserver
我建议使用 Okta Spring Boot starter。它缩短了
spring.security.oauth2.*
属性以更加直观。
okta.oauth2.issuer=<your-issuer>
okta.oauth2.client-id=<your-client-id>
okta.oauth2.client-secret=<your-client-secret>
如果你想使用 Spring Security,我建议使用以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
然后,配置如下:
spring:
security:
oauth2:
client:
provider:
okta:
issuer-uri: <your-issuer>
registration:
okta:
client-id: <your-client-id>
client-secret: <your-client-secret>
scope: openid,profile,email
有时仅与身份验证相关的应用程序属性和 Maven 配置是不够的。
让我们尝试显式启用 spring 的自动配置属性并创建默认值
ClientRegistrationRepository
& OAuth2AuthorizedClientRepository
(两者都是您的过滤器功能所必需的)
build.gradle
dependencies {
implementation "org.springframework.boot:spring-boot-starter-oauth2-client"
}
Java
@Configuration
@EnableWebSecurity
@EnableAutoConfiguration
@EnableConfigurationProperties(OAuth2ClientProperties.class)
public class OAuth2Config {
@Bean
@ConditionalOnMissingBean
public ClientRegistrationRepository clientRegistrationRepository(
OAuth2ClientProperties oAuth2ClientProperties) {
var clientRegistrations =
List.copyOf(
new OAuth2ClientPropertiesMapper(oAuth2ClientProperties)
.asClientRegistrations()
.values());
return new InMemoryClientRegistrationRepository(clientRegistrations);
}
@Bean
@ConditionalOnMissingBean
public OAuth2AuthorizedClientService authorizedClientService(
ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
@Bean
@ConditionalOnMissingBean
public OAuth2AuthorizedClientRepository authorizedClientService(
OAuth2AuthorizedClientService authorizedClientService) {
return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
}
}