Spring应用程序上下文中的Spring Bean依赖关系形成了一个循环。

huangapple go评论68阅读模式
英文:

Spring bean dependencies in the application context form a cycle

问题

我一直在尝试为我的项目添加JWT授权。我已经尝试过添加@Lazy,但没有起作用。
我不知道如何更新我的应用程序以移除依赖循环。

控制台:

应用程序上下文中某些bean的依赖关系形成循环:

┌─────┐
| jwtAuthenticationFilter 定义在文件 [C:\Users\User\Desktop\PizzaCloud2\target\classes\pizzas\security\authentication\JwtAuthenticationFilter.class]
↑     ↓
| securityConfig 定义在文件 [C:\Users\User\Desktop\PizzaCloud2\target\classes\pizzas\security\SecurityConfig.class]
└─────┘


操作:

不鼓励依赖循环,并且默认情况下是被禁止的。请更新您的应用程序以删除bean之间的依赖循环。作为最后的手段,可以通过将 spring.main.allow-circular-references 设置为 true 来尝试自动打破循环。

JwtAuthenticationFilter类:

@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter{
	
	private final JwtService jwtService;
	private final UserDetailsService userDetailsService;

	@Override
	protected void doFilterInternal(
			@NonNull HttpServletRequest request, 
			@NonNull HttpServletResponse response, 
			@NonNull FilterChain filterChain)
					throws ServletException, IOException {
		
		final String authHeader = request.getHeader("Authorization");
		final String jwt;
		final String username;
		if (authHeader == null || !authHeader.startsWith("Bearer")) {
			filterChain.doFilter(request, response);
			return;
		}
		jwt = authHeader.substring(7);
		username = jwtService.extractUsername(jwt);
		if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
			UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
			if (jwtService.isTokenValid(jwt, userDetails)) {
				UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
					userDetails, userDetails.getAuthorities()
				);
				authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
				SecurityContextHolder.getContext().setAuthentication(authToken);
			}
		}
		filterChain.doFilter(request, response);
	}
}

SecurityConfig类:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
	
	private final JwtAuthenticationFilter jwtAuthFilter;
	private final AuthenticationProvider authenticationProvider;
  
	@Bean
	public UserDetailsService userDetailsService(UserRepository userRepo) {
		return username -> {
			User2 user = userRepo.findByUsername(username);
			if (user != null) {
				return user;
			}
			throw new UsernameNotFoundException(
					"用户 '" + username + "' 未找到");
		};
	}
  
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		
		http
		.authenticationProvider(authenticationProvider)
		.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
		
		return http.csrf()
				.disable()
				/*.authorizeRequests()*/
				.authorizeHttpRequests()
				.requestMatchers("/design", "/orders").hasRole("USER")
				.anyRequest().permitAll()
				/*.anyRequest().authenticated()*/
			  
				.and()
				.sessionManagement()
				.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
			  
				.and()
				.formLogin()
				.loginPage("/login")

				.and()
				.logout()
				.logoutSuccessUrl("/")
				
      // 让H2-Console不受保护;用于调试目的
			  /*.and()
			  .csrf()
			  .ignoringRequestMatchers("/h2-console/**")*/

      // 允许从同一来源加载帧的页面;H2-Console所需
				.and()  
				.headers()
				.frameOptions()
				.sameOrigin()
		
				.and()
				.build();
		}
}

将spring.main.allow-circular-references设置为true也没有帮助。

英文:

I've been trying to add jwt authorisation to my project. I've already tried adding @Lazy, that doesn't work.
I don't know how can I update my app to remove the dependency cycle.

Console:

The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  jwtAuthenticationFilter defined in file [C:\Users\User\Desktop\PizzaCloud2\target\classes\pizzas\security\authentication\JwtAuthenticationFilter.class]
↑     ↓
|  securityConfig defined in file [C:\Users\User\Desktop\PizzaCloud2\target\classes\pizzas\security\SecurityConfig.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

JwtAuthenticationFilter class:

@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter{
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request, 
@NonNull HttpServletResponse response, 
@NonNull FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Äuthorization");
final String jwt;
final String username;
if (authHeader == null || !authHeader.startsWith("Bearer")) {
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, userDetails.getAuthorities()
);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}

SecurityConfig class:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public UserDetailsService userDetailsService(UserRepository userRepo) {
return username -> {
User2 user = userRepo.findByUsername(username);
if (user != null) {
return user;
}
throw new UsernameNotFoundException(
"User '" + username + "' not found");
};
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.csrf()
.disable()
/*.authorizeRequests()*/
.authorizeHttpRequests()
.requestMatchers("/design", "/orders").hasRole("USER")
.anyRequest().permitAll()
/*.anyRequest().authenticated()*/
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutSuccessUrl("/")
// Make H2-Console non-secured; for debug purposes
/*.and()
.csrf()
.ignoringRequestMatchers("/h2-console/**")*/
// Allow pages to be loaded in frames from the same origin; needed for H2-Console
.and()  
.headers()
.frameOptions()
.sameOrigin()
.and()
.build();
}
}

Setting spring.main.allow-circular-references to true doesn't help.

答案1

得分: 0

根据错误提示:“依赖循环引用是不鼓励的,而且默认情况下是禁止的...”

  • JwtAuthenticationFilter 在 SecurityConfig 中引用了 UserDetailsService

  • SecurityConfig 引用了 JwtAuthenticationFilter

解决方案:您可以将 @Bean UserDetailsService 移动到另一个配置类中。

英文:

As the error indicating: "Relying upon circular references is discouraged and they are prohibited by default..."

  • JwtAuthenticationFilter refer UserDetailsService in SecurityConfig

  • SecurityConfig refer JwtAuthenticationFilter

Solution: You can move @Bean UserDetailsService to another configuration class

huangapple
  • 本文由 发表于 2023年1月9日 17:22:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75055229.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定