2024-10-28T12:59:40.730+03:00 ОШИБКА 998 --- [restartedMain] o.s.boot.SpringApplication: Приложение Ошибка запуска
org.springframework.beans.factory.UnsatisfiedDependencyException: ошибка при создании bean-компонента с именем «org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration»: неудовлетворенная зависимость, выраженная через Параметр метода setFilterChains 0: ошибка при создании bean-компонента с именем SecurityFilterChain, определенным в ресурсе пути к классу [com/chama/chamaservice/config/SecurityConfig.class]: не удалось создать экземпляр [org.springframework.security.web.SecurityFilterChain]: Factory метод 'securityFilterChain' выдал исключение с сообщением: Этот объект уже построен
Ошибка произошла после внесения значительных обновлений в мои пакеты в pom.xml, поскольку они сильно устарели.
Эта ошибка возникает из моего класса конфигурации безопасности, который выглядит следующим образом:
Код: Выделить всё
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity(
securedEnabled = true, // Enables @Secured annotation support
jsr250Enabled = true, // Enables @RolesAllowed annotation support
prePostEnabled = true // Enables @PreAuthorize and @PostAuthorize annotation support
)
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final UserRepository userRepository;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManager(http), userRepository);
customAuthenticationFilter.setFilterProcessesUrl("/api/login");
http
.csrf(AbstractHttpConfigurer::disable) // Disable CSRF
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // Stateless sessions
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/api/login/**",
"/api/token/refresh/**",
"/api/users/save/**",
"/api/health/**",
"/api/daraja/c2b/validate/**",
"/api/daraja/c2b/confirm/**"
)
.permitAll() // Permit specific endpoints
.anyRequest().authenticated() // Require authentication for all other endpoints
)
.addFilter(customAuthenticationFilter) // Add authentication filter
.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class); // Add authorization filter
return http.build();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder auth = http.getSharedObject(AuthenticationManagerBuilder.class);
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
return auth.build();
}
}
У меня также есть класс CustomAuthenticationFilter, который обрабатывается securityFilterChain, который выглядит следующим образом:
Код: Выделить всё
@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private final UserRepository userRepository;
@Value("${security.jwt.secret}")
private String jwtSecret = "x!A%D*G-KaPdSgVkYp3s6v9y/B?E(H+MbQeThWmZq4t7w!z%C&F)J@NcRfUjXn2r";
public CustomAuthenticationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String phoneNumber = request.getParameter("phoneNumber");
String password = request.getParameter("password");
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phoneNumber, password);
return authenticationManager.authenticate(authenticationToken);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ResourceNotFoundException {
User user = (User) authResult.getPrincipal();
com.chama.chamaservice.user.User principal = userRepository.findByUsername(user.getUsername()).orElseThrow(() -> new ResourceNotFoundException(MessageUtil.ERROR_USER_NOTFOUND));
Algorithm algorithm = Algorithm.HMAC256(jwtSecret.getBytes(StandardCharsets.UTF_8));
String accessToken = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 60 * 60 * 1000))
.withIssuer(request.getRequestURL().toString())
.withClaim("userId", principal.getId())
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
String refreshToken = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 300 * 60 * 1000))
.withIssuer(request.getRequestURL().toString())
.sign(algorithm);
Map userProfile = new HashMap();
userProfile.put("access_token", accessToken);
userProfile.put("refresh_token", refreshToken);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), userProfile);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
Map error = new HashMap();
error.put("message", MessageUtil.UNSUCCESSFUL_AUTHENTICATION);
response.setContentType(APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
}
Код: Выделить всё
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">
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.2.7
com.chama
chamaservice
0.0.1-SNAPSHOT
chamaservice
Chama Contribution Service
com.chama.chamaservice.GroupServiceApplication
17
jakarta.persistence
jakarta.persistence-api
3.1.0
org.hibernate.orm
hibernate-core
6.6.1.Final
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-test
test
org.springframework.security
spring-security-test
test
org.testcontainers
testcontainers
1.20.3
test
org.springframework.boot
spring-boot-starter-webflux
com.auth0
java-jwt
3.19.2
org.yaml
snakeyaml
2.0
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
8.0.33
runtime
org.springframework.boot
spring-boot-configuration-processor
true
jakarta.validation
jakarta.validation-api
3.1.0
jakarta.transaction
jakarta.transaction-api
2.0.0
jakarta.servlet
jakarta.servlet-api
5.0.0
provided
org.projectlombok
lombok
1.18.26
provided
io.projectreactor.netty
reactor-netty
io.netty
netty-resolver-dns-native-macos
4.1.76.Final
runtime
org.testcontainers
junit-jupiter
1.16.2
test
org.testcontainers
mysql
1.16.2
test
com.google.guava
guava
32.0.0-android
org.springframework.data
spring-data-redis
3.3.4
com.h2database
h2
2.1.210
test
org.assertj
assertj-core
3.17.2
test
org.springframework.boot
spring-boot-starter-validation
3.3.1
org.springframework.boot
spring-boot-maven-plugin
org.project-lombok
lombok
chamaservice-image
com.chama.chamaservice.GroupServiceApplication
JAR
repackage
org.apache.maven.plugins
maven-compiler-plugin
3.11.0
17
17
Вместо этого я попробовал вернуть http.getOrBuild(); из http.build();. Это устранило ошибку, но requestMatchers не работал, ссылаясь на 401 Unauthorized.
Я также проверил здесь другие подобные проблемы с переполнением стека, хотя некоторые из них были очень похожи, но они не решали мою ситуацию.
Подробнее здесь: https://stackoverflow.com/questions/791 ... ory-method