由于重复的Bean注册httpSessionManager,无法在Spring Boot 2.1中使用Keycloak

Tob*_*ler 28 spring-security spring-boot keycloak

我想用Keycloak 4.5保护我的Spring Boot 2.1应用程序.

目前,由于以下错误,我无法启动该应用程序:

Exception encountered during context initialization - cancelling refresh attempt: 
org.springframework.beans.factory.support.BeanDefinitionOverrideException: 
  Invalid bean definition with name 'httpSessionManager' defined in class path resource [dummy/service/SecurityConfig.class]: 
    Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=securityConfig; factoryMethodName=httpSessionManager; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [dummy/SecurityConfig.class]] for bean 'httpSessionManager': 
There is already [Generic bean: class [org.keycloak.adapters.springsecurity.management.HttpSessionManager]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/.m2/repository/org/keycloak/keycloak-spring-security-adapter/4.5.0.Final/keycloak-spring-security-adapter-4.5.0.Final.jar!/org/keycloak/adapters/springsecurity/management/HttpSessionManager.class]] bound.
Run Code Online (Sandbox Code Playgroud)

我的类SecurityConfig(见下文)扩展自KeycloakWebSecurityConfigurerAdapter.此适配器已定义bean httpSessionManager.

我理解为什么这是一个问题.问题是,我该如何防止这种情况或解决我的冲突?

到目前为止我所做的步骤:

  • 使用以下方法构建我的pom(见下文):
    • 弹簧引导启动的Web
    • 弹簧引导启动安全
    • keycloak弹簧引导起动
    • dependencyManagement中的keycloak-adapter-bom
  • 定义了一个扩展KeycloakWebSecurityConfigurerAdapter的自己的SecurityConfig

的pom.xml

...
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <java.version>11</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>

    <keycloak.version>4.5.0.Final</keycloak.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>${keycloak.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
...
Run Code Online (Sandbox Code Playgroud)

SecurityConfig.java

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(KeycloakWebSecurityConfigurerAdapter.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Bean
    public KeycloakConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().ignoringAntMatchers("/**/*");
        http.authorizeRequests()
                .anyRequest().permitAll();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新 有一个已知问题(KEYCLOAK-8725).该修复计划为5.x的Keycloak.但是,评论中有一个解决方法.只需将注释@KeyCloakConfiguration替换为:

@Configuration
@ComponentScan(
    basePackageClasses = KeycloakSecurityComponents.class,
    excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"))
@EnableWebSecurity
Run Code Online (Sandbox Code Playgroud)

Yur*_*kov 26

这有助于我解决问题,删除@KeycloakConfiguration并使用它(来自KEYCLOAK-8725):

Java的:

@Configuration
@ComponentScan(
        basePackageClasses = KeycloakSecurityComponents.class,
        excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"))
@EnableWebSecurity
Run Code Online (Sandbox Code Playgroud)

科特林:

@Configuration
@ComponentScan(
    basePackageClasses = [KeycloakSecurityComponents::class],
    excludeFilters = [ComponentScan.Filter(type = FilterType.REGEX, pattern = ["org.keycloak.adapters.springsecurity.management.HttpSessionManager"])]
)
@EnableWebSecurity
Run Code Online (Sandbox Code Playgroud)

  • 干净而优雅的解决方案。有用! (5认同)

And*_*son 18

看起来Keycloak的Spring Security集成中存在一个错误,这意味着子类的应用程序KeycloakWebSecurityConfigurerAdapter将尝试创建两个名为bean的bean httpSessionManager.当使用相同的名称定义两个bean时,遇到的第二个定义将尝试覆盖第一个.Spring Boot 2.1中默认禁止这种覆盖.我建议将此报告为针对Keycloak的Spring Security集成的错误.当你正在等待错误得到解决,您可以通过设置解决该问题spring.main.allow-bean-definition-overriding=trueapplication.properties.

  • 谢谢,这帮助我找到了问题([KEYCLOAK-8725](https://issues.jboss.org/browse/KEYCLOAK-8725?focusedCommentId=13660313&amp;page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment- tabpanel#comment-13660313))。 (3认同)

Sha*_*att 5

解决重复HttpSessionManagerbean 定义的首选方法是覆盖此 bean 的创建SecurityConfig,并在其实例化上添加条件注释,如下所示:

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(KeycloakWebSecurityConfigurerAdapter.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    @Bean
    @Override
    @ConditionalOnMissingBean(HttpSessionManager.class)
    protected HttpSessionManager httpSessionManager() {
        return new HttpSessionManager();
    }
}
Run Code Online (Sandbox Code Playgroud)