所以我尝试使用 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的这个错误。
即使这样,也会出现其他一些问题,例如蚂蚁匹配。
您所报告的问题的答案由Andrei Lisa在他的回答中给出。您应该对他链接的答案投赞成票。
但是,您报告的配置中还有很多其他错误:
securityMatcher
=> 它将拦截所有请求,并且资源服务器过滤器链永远不会有机会被尝试。/login/**
和 /oauth2/**
的访问应由您的客户端过滤器链处理,并在 permitAll
路由中列出(如果您想登录工作)LogoutHandler
和 LogoutSuccessHandler
不是同一件事)。如果使用“我的”启动器,您将根本没有 Java 配置,并且避免了您报告的问题以及我列出的所有问题。