引起:java.lang.IllegalArgumentException:必须指定authenticationManager

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

引起:org.springframework.beans.factory.BeanCreationException:创建文件 [mypath\security ilter\AuthenticationFilter.class] 中定义的名为“authenticationFilter”的 bean 时出错:必须指定authenticationManager

.

.

原因:java.lang.IllegalArgumentException:必须指定authenticationManager

在解决了我遇到的循环依赖错误后,我开始收到此错误,现在由于某种原因,我的 AuthenticationManager bean 在我的 AuthenticationFilter 中为空

(这让我觉得我并没有真正解决它,程序现在只是提前中断了)

我的安全配置:

@Configuration
public class SecurityConfig {

    @Autowired
    private AuthenticationFilter authenticationFilter;

    /***
     * This method is used to configure the security filter chain
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        authenticationFilter.setFilterProcessesUrl("/user/login");

        http
                .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) //h2-console fix
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(c -> c
                        .requestMatchers("/user/login", "/user/register", "/h2-console", "/h2-console/*").permitAll()
                        .anyRequest().authenticated())
                .addFilterBefore(new ExceptionHandlerFilter(), AuthenticationFilter.class)
                .addFilter(authenticationFilter);
        return http.build();
    }
}

然后是我的 AuthenticationFilter

@Component
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try{
            User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            Authentication authentication = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
            return authenticationManager.authenticate(authentication);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        super.successfulAuthentication(request, response, chain, authResult);
    }

}

我的自定义身份验证管理器

@Component
public class CustomAuthenticationManager implements AuthenticationManager {

    @Autowired
    private UserService userService;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        User user = userService.getUser(authentication.getName());
        if(!userService.validatePassword(authentication.getCredentials().toString(), user.getPassword())){
            throw new BadCredentialsException("Invalid password");
        }
        return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials());
    }
}

和我的 UserServiceImpl

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private static BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ModelMapper modelMapper;

    @Override
    public UserDto saveUser(UserDto userDto) {
        userDto.setPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));
        return convertToDto(userRepository.save(convertToEntity(userDto)));
    }

    @Override
    public User getUser(String email){
        Optional<User> user = userRepository.findByEmail(email);
        return unwrapUser(user);
    }

    public boolean validatePassword(String password, String encodedPassword){
        return bCryptPasswordEncoder.matches(password, encodedPassword);
    }

    static User unwrapUser(Optional<User> user) {
        if(user.isPresent()){
            return user.get();
        }
        else throw new EntityNotFoundException("User not found");
    }

    private UserDto convertToDto(User user) {
        return modelMapper.map(user, UserDto.class);
    }

    private User convertToEntity(UserDto userDto){
        return modelMapper.map(userDto, User.class);
    }
}

这里仍然存在我所缺少的循环依赖吗?
如果不是,是什么导致我的 AuthenticationFilter 中的authenticationManager为空?

另外,您对我将来如何调试此类错误有什么建议吗?

尝试通过构造函数而不是@Autowired注入依赖项,但结果相同 也尝试将 AuthenticationManager bean 更改为实际实现,但错误是相同的

java spring-boot maven
1个回答
0
投票

这不是由循环引用引起的,而是因为您没有满足过滤器超类的要求。

你的课程延长了

UsernamePasswordAuthenticationFilter
延伸
AbstractAuthenticationProcessingFilter
。 AbstractAuthenticationProcessingFilter 实现接口
InitializingBean
,其中包含方法
afterPropertiesSet
。在此方法中,您将看到它检查是否设置了authenticationManager。由于您没有设置它,因此断言失败。

解决此问题有两种方法:

最简单的方法是从 AuthenticationManager 中删除 Autowired 注释并将其设置在构造函数中,同时调用 super。

@Component
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {

  private final AuthenticationManager authenticationManager;

  public AuthenticationFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
    this.authenticationManager = authenticationManager;
  }
}

另一种方法也同样简单:将 AuthenticationFilter 保持原样,但添加

setAuthenticationManager
的实现。

@Override
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
    super.setAuthenticationManager(authenticationManager);
}

其中任何一个都应该可以解决您的问题。

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