首页 > 解决方案 > 使用“spring-boot-starter-oauth2-resource-server”设置资源服务器时,不会自动注入 JwtDecoder bean

问题描述

我正在使用“spring-boot-starter-oauth2-resource-server”设置资源服务器:

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server'

我设置了一个简单的安全配置,如下所示:

@Configuration
@EnableWebSecurity
class EndpointsSecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/live")
    }

    override fun configure(http: HttpSecurity?) {
        http?.cors()
        http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        http?.csrf()?.disable()
        http
            ?.authorizeRequests()
            ?.anyRequest()
            ?.authenticated()
            ?.and()
            ?.oauth2ResourceServer()
            ?.jwt()
    }
}

在我的 application.yml 中,我添加了 issuer-uri,如下所示:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://cognito-idp.${AWS_REGION:eu-central-1}.amazonaws.com/${COGNITO_USER_POOL_ID:testUserPoolId}

正如我在许多教程和官方文档中看到的那样,这个配置是简约的,应该可以在没有任何额外配置的情况下开箱即用,但是我的应用程序无法启动并出现以下错误:

Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.oauth2.jwt.JwtDecoder' available
   at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)

所以这里的问题是,即使在 OAuth2ResourceServerJwtConfiguration 类中声明了 JwtDecoder bean 并且受我在 application.yml 中设置的 issuer-uri 条件限制,也找不到 JwtDecoder bean。

作为一种解决方法,我自己重新声明了 bean,如下所示:

@Configuration
@EnableWebSecurity
class EndpointSecurityConfig(@Value("\${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private val issuerUri: String) : WebSecurityConfigurerAdapter() {

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/live")
    }

    override fun configure(http: HttpSecurity?) {
        http?.cors()
        http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        http?.csrf()?.disable()
        http
            ?.authorizeRequests()
            ?.anyRequest()
            ?.authenticated()
            ?.and()
            ?.oauth2ResourceServer()
            ?.jwt()
    }

    @Bean
    @Conditional(IssuerUriCondition::class)
    fun jwtDecoderByIssuerUri(): JwtDecoder? {
        return JwtDecoders.fromIssuerLocation(issuerUri)
    }
}

这是有效的,但我无法弄清楚为什么开箱即用的配置对我不起作用?

更新:gradle 配置


plugins {
    id 'java'
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "org.springframework.boot" version "2.2.5.RELEASE"
    id "org.owasp.dependencycheck" version "6.0.2"
}

// irrelevent details

dependencies {
    ktlint "com.pinterest:ktlint:0.34.2"

    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: '1.3.70'
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.3.70'
    implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.3.0'

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server', version: '2.3.4.RELEASE'

    implementation group: 'com.amazonaws', name: 'aws-java-sdk-secretsmanager', version: "1.11.875"

    implementation group: 'com.oracle.database.jdbc', name: 'ojdbc8', version: "19.7.0.0"

    implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.10.2'

    implementation group: 'org.springdoc', name: 'springdoc-openapi-kotlin', version: '1.4.3'
    implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.4.3'

    runtime group: 'com.h2database', name: 'h2', version: '1.4.194'

    testImplementation group: 'io.mockk', name: 'mockk', version: '1.9.3'
    testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.3.4.RELEASE'
    testImplementation group:'org.springframework.security', name: 'spring-security-test'
}

标签: spring-bootkotlinspring-securityoauth-2.0jwt

解决方案


我发现我正在处理的项目的 gradle 配置存在问题(更新了问题)。Spring Boot 依赖项是使用版本“2.3.4.RELEASE”声明的,而org.springframework.boot插件版本是“2.2.5.RELEASE”,我认为这一定导致了 spring 依赖项之间的某种不兼容。

作为解决方案,我从 spring 依赖项中删除了版本声明,并将插件版本设置为“2.3.4.RELEASE”,现在错误消失了,oauth2 资源服务器配置可以在没有任何额外配置的情况下工作。

注意:

I noticed that when I keep the plugin version at "2.2.5.RELEASE" the error persist and the out of the box config doesn't work unless I remove the plugin io.spring.dependency-management.


推荐阅读