java 未找到类异常:org.springframework.security.oauth2.server.resource.web.BearerTokenResolver

6l7fqoea  于 2023-03-28  发布在  Java
关注(0)|答案(2)|浏览(348)

我在使用Spring Security oauth2 vs Keycloak进行验证时出现相关错误。我不认为它在我的依赖项中丢失了。

错误

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Unsatisfied dependency expressed through method 'setFilterChains' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'filterChain' defined in class path resource [com/framework/security/SecurityConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/security/oauth2/server/resource/web/BearerTokenResolver
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:767) ~[spring-beans-5.3.23.jar:5.3.23]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.3.23.jar:5.3.23]
        at 
    Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.server.resource.web.BearerTokenResolver
        at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?]

我的安全类

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/login/**").hasRole("role-name").anyRequest().authenticated().and().oauth2ResourceServer().jwt();
        return http.build();
    }
}

聚合物.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>
    </dependencies>

应用程序.yml

security:
    oauth2:
      resource-server:
        jwt:
          issuer-uri: http://keycloak-url/realms/realm-id
          jwk-set-uri: http://keycloak-url/realms/realm-id/protocol/openid-connect/certs
      client:
        registration:
          client-ui:
            provider: keycloak
            client-id: client-ui
            client-secret: abcdefgh
            authorization-grant-type: authorization_code
            scope: openid
        provider:
          client-ui:
            authorization-uri: http://keycloak-url/realms/realm-id/protocol/openid-connect/auth
            token-uri: http://keycloak-url/realms/realm-id/protocol/openid-connect/token
            user-info-uri: http://keycloak-url/realms/realm-id/protocol/openid-connect/userinfo
            jwk-set-uri: http://keycloak-url/realms/realm-id/protocol/openid-connect/certs
            user-name-attribute: preferred_username

我试着做了很多编辑,但我找不到问题。我怎么能解决它呢?

muk1a3rh

muk1a3rh1#

首先,你应该决定你的应用主要是一个OAuth2客户端还是一个OAuth2资源服务器。在这里,你在同一个安全过滤器链中混合了客户端和资源服务器配置。这是行不通的。我写了一个“OAuth2要点”部分作为my tutorials的介绍,这应该有助于你做出决定。

Servlet资源服务器(REST API)

资源服务器不关心登录或OAuth2流,这是客户端关注的。它只关心请求是否被授权(具有有效的访问令牌),该令牌是否应该被内省或解码,以及是否应该基于令牌声明授予对所请求资源的访问。
使用Postman或任何OAuth2客户端,它们可以授权其请求并发送任何类型的请求(不仅是GET,还包括POST,PUT和DELETE)来尝试您正在运行的API。

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
@SpringBootApplication
public class ResourceServerMinimalApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourceServerMinimalApplication.class, args);
    }

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Bean
    SecurityFilterChain resourceServerSecurityFilterChain(
            HttpSecurity http,
            @Value("${resource-server.cors.allowed-origins:}#{T(java.util.Collections).emptyList()}") List<String> allowedOrigins)
            throws Exception {
        http.oauth2ResourceServer(oauth2 -> oauth2.jwt());
        http.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        http.csrf(csrf -> csrf.disable());
        http.exceptionHandling(handeling -> handeling.authenticationEntryPoint((request, response, authException) -> {
            response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
            response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
        }));
        http.authorizeHttpRequests().anyRequest().authenticated();
        http.cors(cors -> {
            if (allowedOrigins.isEmpty()) {
                cors.disable();
            } else {
                cors.configurationSource(corsConfig(allowedOrigins));
            }
        });
        return http.build();
    }

    CorsConfigurationSource corsConfig(List<String> allowedOrigins) {
        final var source = new UrlBasedCorsConfigurationSource();

        final var configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(allowedOrigins);
        configuration.setAllowedMethods(List.of("*"));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setExposedHeaders(List.of("*"));

        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @RestController
    @RequestMapping("/api/v1")
    public static class GreetingController {
        @GetMapping("/greet")
        public ResponseEntity<GreetingDto> getGreeting(Authentication auth) {
            return ResponseEntity.ok(new GreetingDto("Hello %s!".formatted(auth.getName())));
        }

        static record GreetingDto(String message) {
        }
    }
}
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://keycloak-url/realms/realm-id

resource-server:
  cors:
    allowed-origins:
    - http://localhost:4200

Servlet客户端(服务Thymeleaf模板)

一个一个三个一个一个一个一个一个四个一个一个一个一个一个五个一个
/src/main/resources/templates/greet.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <title>Greetings!</title>
</head>

<body>
    <h1 th:utext="${message}">..!..</h1>
</body>

客户端与资源服务器结合

如果您的应用同时公开REST API和服务器端呈现的UI来操作它(仅在这种情况下),请定义上面的两个不同的过滤器链,并在第一个链上添加securityMatcher,以将其限制为应该保护的路由。

在上面提供的示例中,具有最低顺序的安全过滤器链是资源服务器链。添加类似http.securityMatcher("/api/**");的东西可以做到这一点:所有其它路由将利用客户端过滤器链来保护,该客户端过滤器链在之后被尝试并且将拦截尚未被资源服务器过滤器链拦截的所有请求。

yquaqz18

yquaqz182#

也许,您在pom.xml中缺少了oauth2-resource-server依赖项

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-oauth2-resource-server</artifactId>
  <version>6.0.2</version>
</dependency>

这实际上会自动附加所需的DefaultBearerTokenResolver Bean,并且应该可以开箱即用。

相关问题