Spring Security 循环依赖

问题描述 投票:0回答:1

我的 SecurityConfiguration 和 CustomAuthenticationFilter 之间存在循环依赖关系。我认为 AuthenticationManager 是问题所在,我无法解决它。

安全配置

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfiguration {
    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final CredentialsAuthenticationFilter credentialsAuthenticationFilter;
    private final CustomUserDetailsService userDetailsService;
    private final LogoutHandler logoutHandler;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(registry -> registry
                        .requestMatchers(HttpMethod.POST, "/api/v1/trainees",
                                "/api/v1/trainers").permitAll()
                        .anyRequest().authenticated())
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(credentialsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .logout(logout -> logout
                        .logoutUrl("/api/v1/users/logout")
                        .addLogoutHandler(logoutHandler)
                        .logoutSuccessHandler((request, response, authentication) -> {
                            SecurityContextHolder.clearContext();
                        }));
        return http.build();
    }

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

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(List.of("http://localhost:8081"));
        corsConfiguration.setAllowedMethods(List.of("OPTIONS", "HEAD", "GET", "PUT", "POST", "DELETE", "PATCH"));
        corsConfiguration.setAllowedHeaders(List.of("Authorization"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}

凭证身份验证过滤器

@Component
public class CredentialsAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final AuthenticationManager authenticationManager;
    private final JwtIssuer jwtIssuer;
    private final TokenService tokenService;
    private final UserService userService;

    public CredentialsAuthenticationFilter(
            @Lazy AuthenticationManager authenticationManager,
            JwtIssuer jwtIssuer,
            TokenService tokenService,
            UserService userService
    ) {
        this.authenticationManager = authenticationManager;
        this.jwtIssuer = jwtIssuer;
        this.tokenService = tokenService;
        this.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/api/v1/users/login", "POST"));
        this.userService = userService;
    }

    @Override
    public Authentication attemptAuthentication(
            HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException {
        try {
            InputStream requestBody = request.getInputStream();
            AuthDTORequest authDTORequest = new ObjectMapper().readValue(requestBody, AuthDTORequest.class);
            String username = authDTORequest.getUsername();
            String password = authDTORequest.getPassword();
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(username, password);
            return authenticationManager.authenticate(authenticationToken);
        } catch (IOException e) {
            throw new SCAuthenticationException("Authentication failed");
        }

    }

    @Override
    protected void successfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain,
            Authentication authResult) throws IOException, ServletException {
        UserPrincipal principal = (UserPrincipal) authResult.getPrincipal();
        String accessToken = jwtIssuer.issue(principal.getId(), principal.getUsername());
        UserEntity user = userService.findByUsername(principal.getUsername());
        tokenService.revokeAllUserTokens(user.getId());
        TokenEntity token = new TokenEntity(
                accessToken,
                TokenType.BEARER,
                false,
                false,
                user);
        tokenService.save(token);
        AuthDTOResponse authDTOResponse = new AuthDTOResponse(accessToken);
        response.getWriter().write(new ObjectMapper().writeValueAsString(authDTOResponse));
        chain.doFilter(request, response);
    }

    @Override
    protected void unsuccessfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException failed) throws IOException, ServletException {
        super.unsuccessfulAuthentication(request, response, failed);
        throw new SCAuthenticationException("Authentication failed.");
    }
}

我尝试应用惰性注释,但它没有帮助,我收到此错误

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'credentialsAuthenticationFilter' defined in file [/CredentialsAuthenticationFilter.class]: authenticationManager must be specified
java spring-boot spring-security
1个回答
0
投票

根据

AuthenticationConfiguration
,注入的bean中有
AuthenticationManagerBuilder
,但是没有
AuthenticationManager
。根据
HttpSecurity.beforeConfigure()
AuthenticationManager
可以从
sharedObject

获得
© www.soinside.com 2019 - 2024. All rights reserved.