尝试解析 AuthenticationManager(Spring 安全和 Oauth)时检测到依赖循环

A dependency cycle was detected when trying to resolve the AuthenticationManager (Spring Security and Oauth)

我在配置 spring 安全性时遇到以下错误,有人可以帮助我吗?当前配置资源服务器和认证服务器在同一个服务器进行测试,可能会造成冲突。

Caused by: org.springframework.beans.FatalBeanException: A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.validateBeanCycle(WebSecurityConfigurerAdapter.java:462)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.<init>(WebSecurityConfigurerAdapter.java:430)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.authenticationManagerBean(WebSecurityConfigurerAdapter.java:220)
    at org.blanc.whiteboard.security.configuration.SecurityConfig$ApiWebSecurityConfig.configure(SecurityConfig.java:110)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:199)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:283)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:68)
    at org.blanc.whiteboard.security.configuration.SecurityConfig$ApiWebSecurityConfig$$EnhancerBySpringCGLIB$cbb9c9d.init(<generated>)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:367)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:320)
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:39)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:92)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e.CGLIB$springSecurityFilterChain(<generated>)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e$$FastClassBySpringCGLIB$d548252.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e.springSecurityFilterChain(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
    ... 30 more

网络安全

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Bean
    public OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler(){
        return new OAuth2AccessDeniedHandler();
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
        @Autowired
        private UserRepository userRepository;

        @Autowired
        private Validator validator;

        @Bean
        public PasswordEncoder passwordEncoder(){
            return new StandardPasswordEncoder();
        }

        @Autowired
        private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Bean
        public OAuthRestEntryPoint oauthRestEntryPoint()
        {
            return new OAuthRestEntryPoint();
        }

//      @Bean(name = "authenticationManager")
//      @Override
//      public AuthenticationManager authenticationManagerBean()
//              throws Exception {
//          return super.authenticationManagerBean();
//      }

        @Bean
        public ClientDetailsUserDetailsService clientDetailsUserDetailsService(){
            return new ClientDetailsUserDetailsService(clientDetailsService);
        }
        @Bean
        public UserDetailsService userDetailsService() {
            return new UserServiceImpl(userRepository, validator, passwordEncoder());
        }

        @Bean
        protected AuthenticationEntryPoint authenticationEntryPoint(){
            OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
            entryPoint.setTypeName("Basic");
            entryPoint.setRealmName("test");
            return entryPoint;
        }



        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.anonymous().disable()
            .antMatcher("/oauth/token")
            .authorizeRequests().anyRequest().authenticated()
            .and()
                .httpBasic().authenticationEntryPoint(oauthRestEntryPoint())
            .and()
                .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/token")).disable()
                .exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
            .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

            ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
            filter.setAuthenticationManager(authenticationManagerBean());
            filter.afterPropertiesSet();
            http.addFilterBefore(filter, BasicAuthenticationFilter.class);
            http.addFilterAfter(filter, SpringCrossOriginResourceSharingFilter.class);
        }


    }
    @Configuration
    @Order(2)
    protected static class ResourceServerConfig extends WebSecurityConfigurerAdapter{

        @Bean(name = "clientAuthenticationManager")
        @Override
        public AuthenticationManager authenticationManagerBean()
                throws Exception {
            return super.authenticationManagerBean();
        }


        @Autowired
        private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
        @Bean
        public OAuth2AuthenticationEntryPoint clientAuthenticationEntryPoint(){
            OAuth2AuthenticationEntryPoint clientAuthenticationEntrypoint = new OAuth2AuthenticationEntryPoint();
            clientAuthenticationEntrypoint.setTypeName("Basic");
            return clientAuthenticationEntrypoint;
        }


        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.anonymous().disable().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
                .authenticationEntryPoint(clientAuthenticationEntryPoint())
            .and()
                .requestMatchers().antMatchers("/v1.0/users")
            .and()
                .authorizeRequests().antMatchers(HttpMethod.POST, "/v1.0/users").permitAll()
            .and()
                .csrf().disable();
        }




    }


}

Oauthserver 配置

@Configuration
@ComponentScan
@EnableResourceServer
@Import(SecurityConfig.class)
@ImportResource({
    "classpath:META-INF/spring/oauth/client-details.xml"
})
public class OAuth2ServerConfig {

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends
            AuthorizationServerConfigurerAdapter {
//      @Autowired
//      private AuthenticationManager authenticationManager;


        @Autowired
        private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(){
            ClientCredentialsTokenEndpointFilter clientFilter = new ClientCredentialsTokenEndpointFilter();
//          clientFilter.setAuthenticationManager(authenticationManager);
            return clientFilter;
        }

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Autowired
        public OAuth2AccessTokenRepository oAuth2AccessTokenRepository;

        @Autowired
        public OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;

        @Bean
        public DefaultTokenServices tokenServices(){
            final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setReuseRefreshToken(true);
            defaultTokenServices.setTokenStore(tokenStore());
            defaultTokenServices.setClientDetailsService(clientDetailsService);
            return defaultTokenServices;
        }

        @Bean
        public OAuth2RepositoryTokenStore tokenStore() {
            return new OAuth2RepositoryTokenStore(oAuth2AccessTokenRepository,
                    oAuth2RefreshTokenRepository);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer)
                throws Exception {
            oauthServer.tokenKeyAccess(
                    "isAnonymous || hasAuthority('ROLE_TRUSTED_CLIENT')")
                    .realm("test");
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients)
                throws Exception {
            clients.withClientDetails(clientDetailsService);
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints
//          .authenticationManager(authenticationManager)
                    .clientDetailsService(clientDetailsService).tokenServices(tokenServices())
                    .tokenStore(tokenStore());
        }
    }

}

在您的 ResourceServerConfig 中,您覆盖了 authenticationManagerBean() 但从未将 authenticationManager 配置为 instructed in the api reference,特别是

Override this method to expose the AuthenticationManager from configure(AuthenticationManagerBuilder) to be exposed as a Bean.

例如...

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.authenticationProvider(new MyCustomAuthProvider());
}

详情见configure(AuthenticationManagerBuilder) reference