记录Springboot 集成 SpringSecurity 5.7时 AuthenticationManager发生的循环依赖问题

问题描述

近期升级了springsecurity版本到5.7,WebSecurityConfig的配置方法由集成优化成了声明Bean的方式,直接上代码

@EnableWebSecurity
@EnableConfigurationProperties(AuthProperties.class)
public class WebSecurityConfig {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private AuthProperties authProperties;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JWTService jwtService;
    @Autowired
    private CacheManager cacheManager;

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                // 基于 token,不需要 csrf
                .csrf().disable()
                // 基于 token,不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 下面开始设置权限
                .authorizeRequests(authorize -> authorize
                        .antMatchers(authProperties.getPermitStatic().toArray(new String[0])).permitAll()
                        .antMatchers(authProperties.getPermitMethod().toArray(new String[0])).permitAll()
                        // 其他地址的访问均需验证权限
                        .anyRequest().authenticated())
                .addFilter(new JWTAuthenticationFilter(authenticationManager, sysUserService, jwtService, userCache()))
                .exceptionHandling().authenticationEntryPoint(new UserAuthenticationEntryPoint()).and()
                // 认证用户时用户信息加载配置,注入springAuthUserService
                .userDetailsService(sysUserService).build();
    }


    /**
     * 获取AuthenticationManager(认证管理器),登录时认证使用
     * @param authenticationConfiguration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }


    /**
     * 密码明文加密方式配置(使用国密SM4)
     * @return
     */
    @Bean
    public static PasswordEncoder passwordEncoder() {
        return new SM4PasswordEncoder();
    }

    @Bean
    UserCache userCache(){
        Cache ca = cacheManager.getCache("userCache");
        return new SpringCacheBasedUserCache(ca);
    }
}

由于配置SecurityFilterChain过滤器链中,使用了JWTAuthenticationFilter,而JWTAuthenticationFilter继承自BasicAuthenticationFilter,需要定义一个AuthenticationManager,代码如下,SecurityFilterChain中需要注入AuthenticationManager,而且需要声明一个AuthenticationManager Bean配置

Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private final UserDetailsService userService;
    private final JWTService jwtService;
    private final UserCache userCache;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, SysUserService userService, JWTService jwtService, UserCache userCache) {
        super(authenticationManager);
        this.userService = userService;
        this.jwtService = jwtService;
        this.userCache = userCache;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
      
        chain.doFilter(request, response);
    }
}

启动时循环依赖

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
|  webSecurityConfig (field private org.springframework.security.authentication.AuthenticationManager com.langchen.minfang.user.config.WebSecurityConfig.authenticationManager)
└──<-──┘


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.


Process finished with exit code 1

解决方法:

在注入AuthenticationManager时使用@Lazy注解,一定要在注入的时候。。。。。。。

    @Lazy
    @Autowired
    private AuthenticationManager authenticationManager;

非常感谢您的提问,以下是一个简单的 Spring Boot 集成 Spring Security OAuth2 的代码示例: @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private DataSource dataSource; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login**", "/error**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/home") .permitAll() .and() .logout() .permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?") .authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?"); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } @Bean public ClientDetailsService clientDetailsService() { JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource); clientDetailsService.setPasswordEncoder(passwordEncoder()); return clientDetailsService; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore()) .authenticationManager(authenticationManagerBean()) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients .withClient("client") .secret(passwordEncoder().encode("secret")) .authorizedGrantTypes("password", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(86400); } } 请注意,这只是一个简单的示例,您需要根据您的实际需求进行修改和扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值