Springboot keycloak oauth2 bean依赖错误

问题描述 投票:0回答:1

所以我尝试使用 Springboot 和 keycloak 授权和身份验证来实现简单的登录表单。我收到此错误:

创建名称为“org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration”的bean时出错:通过方法“setFilterChains”参数0表达的依赖关系不满足:创建类路径资源中定义的名称为“clientFilterChain”的bean时出错[com /login/java/config/SecurityConfig.class]:工厂方法“clientFilterChain”抛出异常并显示消息:此方法无法确定这些模式是否是 Spring MVC 模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher);否则,请使用 requestMatchers(AntPathRequestMatcher)。

原因:org.springframework.beans.factory.UnsatisfiedDependencyException:创建在类路径资源[com/login/java/config/SecurityConfig.class]中定义的名称为“clientFilterChain”的bean时出错:无法实例化[org.springframework.security] .web.SecurityFilterChain]:工厂方法“clientFilterChain”抛出异常并显示消息:此方法无法确定这些模式是否是 Spring MVC 模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher);否则,请使用 requestMatchers(AntPathRequestMatcher)。

引起:org.springframework.beans.BeanInstantiationException:无法实例化[org.springframework.security.web.SecurityFilterChain]:工厂方法“clientFilterChain”抛出异常并显示消息:此方法无法确定这些模式是否是Spring MVC模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher);否则,请使用 requestMatchers(AntPathRequestMatcher)。

错误被缩短为仅需要的行。 KeyCloak 正在 8080 上运行,并带有 Realm Master

SecurityConfig.java

package com.login.java.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import static org.springframework.security.config.Customizer.withDefaults;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

@Configuration  
@EnableWebSecurity  
class SecurityConfig{   
    
    @Autowired
    private final KeycloakLogoutHandler keycloakLogoutHandler;  
    
    @Autowired
    SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {   
        this.keycloakLogoutHandler = keycloakLogoutHandler; 
    }
    
    @Bean
    SessionAuthenticationStrategy sessionAuthenticationStrategy() { 
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());    
    }

    @Order(1)
    @Bean
    SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> authorize
                .requestMatchers(HttpMethod.GET, "/").permitAll()
                .anyRequest().authenticated())
            .oauth2Login(withDefaults())
            .logout(logout -> logout
                .addLogoutHandler(keycloakLogoutHandler)
                .logoutSuccessUrl("/"));    
        return http.build();        
    }


    @Order(2)
    @Bean
    SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> authorize
                .requestMatchers(HttpMethod.GET,"/home*")
                .hasRole("user")
                .anyRequest()
                .authenticated());  
        http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); 
        return http.build();    
    }

    @Bean
    AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {   
        return http.getSharedObject(AuthenticationManagerBuilder.class) 
            .build();   
    }   
}

LoginController.java

package com.login.java;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import com.login.java.model.user;
import com.login.java.model.userInterface;

@Controller
public class LoginController
{
    String lol = "LOL";
    private userInterface userInterface;

    private RestTemplate restTemplate = new RestTemplate();

    @Autowired
     public LoginController(userInterface userInterface) 
     {
        this.userInterface = userInterface;
     }

    @GetMapping(path = "/")
    public String checkMVC()
    {
        return "login";
    }
    
    
    @RequestMapping(path = "/login")
    public String loginHomepage(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            Model model)
    {
        user u;
        System.out.println("Searching for user: " + username);
        u = userInterface.findByUsername(username);
        if (u != null)
        {
            System.out.println("User found: " + u.getUsername());
            model.addAttribute("username", username);
            return "home";
        }

        return "login";
    }

    @RequestMapping(path = "/register")
    public String gotoregisterationpage()
    {
        return "register";
    }

    @RequestMapping(path = "/create-user")
    public String gotoregistermicroservice(
            @RequestParam("username") String username,
            @RequestParam("email") String email,
            @RequestParam("password") String password,
            @RequestParam("cpassword") String cpassword,
            Model model)
    {
        if (password.equals(cpassword))
        {
            // Construct URL with path variables
            String registrationUrl = "http://localhost:8081/register-user/"+username+"/"+password+"/"+email;

            // Create UriComponentsBuilder to build the URL with variables
            UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(registrationUrl);

            // Set path variables
            builder.queryParam("id", 1)
            .queryParam("username", username)
                   .queryParam("password", password)
                   .queryParam("email", email);

            // Make a GET request using RestTemplate
            restTemplate.getForObject(builder.toUriString(), String.class);

            model.addAttribute("registrationSuccess", "Registered Kindly Login!!");
        }
        else
        {
            model.addAttribute("registrationError", "Password Not matching!!");
            return "login";
        }

        return "login";
    }

    @GetMapping(path = "/logout")
    public String logout()
    {
        return "login";
    }
}

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>3.1.2</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.login</groupId>
    <artifactId>microservice</artifactId>
    <version>0.0.1</version>
    <name>skam-login</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>20</java.version>
        <oauth.version>2.3.3.RELEASE</oauth.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </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.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <scope>provided</scope>
            </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>${oauth.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

** 应用程序.属性**

##DB Connection
spring.datasource.url= #has correct URL
spring.datasource.username = #has correct username
spring.datasource.password = #has correct pass
spring.jpa.show-sql = true
spring.jpa.open-in-view= false
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect

##MVC view
spring.mvc.view.prefix = /WEB-INF/
spring.mvc.view.suffix=.jsp
spring.mvc.static-path-pattern=/resources/**

server.port = 8081

##Spring Security
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration

##KeyCloak
spring.security.oauth2.client.registration.keycloak.client-id=keycloak
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid

spring.security.oauth2.client.provider.keycloak.issuer-uri=http://127.0.0.1:8080/realms/master
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://127.0.0.1:8080/realms/master

我的文件夹树结构

│   .classpath
│   .gitignore
│   .project
│   HELP.md
│   mvnw
│   mvnw.cmd
│   pom.xml
│   README.md
│
├───.settings
│       org.eclipse.core.resources.prefs
│       org.eclipse.jdt.apt.core.prefs
│       org.eclipse.jdt.core.prefs
│       org.springframework.ide.eclipse.prefs
│
├───src
│   ├───main
│   │   ├───java
│   │   │   └───com
│   │   │       └───login
│   │   │           └───java
│   │   │               │   LoginController.java
│   │   │               │   SkamLoginmApplication.java
│   │   │               │
│   │   │               ├───config
│   │   │               │       KeycloakLogoutHandler.java
│   │   │               │       RestClientConfiguration.java
│   │   │               │       SecurityConfig.java
│   │   │               │
│   │   │               └───model
│   │   │                       user.java
│   │   │                       userInterface.java
│   │   │
│   │   ├───resources
│   │   │       application.properties
│   │   │
│   │   └───webapp
│   │       └───WEB-INF
│   │               home.jsp
│   │               login.jsp
│   │               register.jsp
│   │
│   └───test
│       ├───java
│       └───resources
└───target
    │   microservice-0.0.1.jar
    │   microservice-0.0.1.jar.original
    │
    ├───classes
    │   │   application.properties
    │   │
    │   ├───com
    │   │   └───login
    │   │       └───java
    │   │           │   LoginController.class
    │   │           │   SkamLoginmApplication.class
    │   │           │
    │   │           ├───config
    │   │           │       KeycloakLogoutHandler.class
    │   │           │       RestClientConfiguration.class
    │   │           │       SecurityConfig.class
    │   │           │
    │   │           └───model
    │   │                   user.class
    │   │                   userInterface.class
    │   │
    │   ├───META-INF
    │   │   │   MANIFEST.MF
    │   │   │
    │   │   └───maven
    │   │       └───com.login
    │   │           └───microservice
    │   │                   pom.properties
    │   │                   pom.xml
    │   │
    │   └───WEB-INF
    │           home.jsp
    │           login.jsp
    │           register.jsp
    │
    ├───generated-sources
    │   └───annotations
    ├───generated-test-sources
    │   └───test-annotations
    ├───maven-archiver
    │       pom.properties
    │
    ├───maven-status
    │   └───maven-compiler-plugin
    │       ├───compile
    │       │   └───default-compile
    │       │           createdFiles.lst
    │       │           inputFiles.lst
    │       │
    │       └───testCompile
    │           └───default-testCompile
    │                   createdFiles.lst
    │                   inputFiles.lst
    │
    └───test-classes

尝试查看Spring Security 6和Spring Cloud的迁移文档但找不到解决方案。

适配器被斩首,所以继续使用spring security资源服务器,遇到了Bean的这个错误。

即使这样,也会出现其他一些问题,例如蚂蚁匹配。

java spring-boot spring-security jwt bean-validation
1个回答
0
投票

您所报告的问题的答案由Andrei Lisa在他的回答中给出。您应该对他链接的答案投赞成票。

但是,您报告的配置中还有很多其他错误:

  • 在具有最高优先级(客户端)的过滤器链中没有
    securityMatcher
    => 它将拦截所有请求,并且资源服务器过滤器链永远不会有机会被尝试。
  • /login/**
    /oauth2/**
    的访问应由您的客户端过滤器链处理,并在
    permitAll
    路由中列出(如果您想登录工作)
  • 您没有配置任何内容来将 Keycloak 角色转换为 Spring 权限。对于客户端和资源服务器来说,这不是以相同的方式完成的。
  • Keycloak 完全符合 OIDC。您应该为 OIDC 使用 Spring Security 注销 sucess 处理程序,而不是定义自己的注销处理程序(
    LogoutHandler
    LogoutSuccessHandler
    不是同一件事)。

如果使用“我的”启动器,您将根本没有 Java 配置,并且避免了您报告的问题以及我列出的所有问题。

© www.soinside.com 2019 - 2024. All rights reserved.