AuthenticationManager.authenticate() 返回 stackoverflow

AuthenticationManager.authenticate() returns stackoverflow

提问人:Alfredo Marin 提问时间:10/13/2023 更新时间:10/13/2023 访问量:44

问:

我正在尝试在我的项目上制作一个简单的登录系统,也使用 Spring 3.1.1 和 Spring Security 3.1.1。阅读文档,我们不应该再“扩展 WebSecurityAdapter”,而是像这样实现它:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    RequestFilter requestFilter;

    /**
     * List with whitelisted endpoints.
     */
    private static final String[] AUTH_WHITELIST = {
            // -- Swagger UI v2
            "/v2/api-docs",
            "/swagger-resources",
            "/swagger-resources/**",
            "/configuration/ui",
            "/configuration/security",
            "/swagger-ui.html",
            "/webjars/**",
            // -- Swagger UI v3 (OpenAPI)
            "/v3/api-docs/**",
            "/swagger-ui/**",
            // other public endpoints of your API may be appended to this array
            "/users/register",
            "/users/login",
            "/plans/free-plan"
    };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(AUTH_WHITELIST).permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(requestFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring().requestMatchers("/v3/api-docs/**");
    }

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

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

在此类中,我在 bean 上创建了一个“AuthenticationManager”,但是当我尝试在我的服务上使用它时,它会给出 Stackoverflow 错误。我的服务:

@Service
public class UserService extends GenericService<User> {

    /**
     * Authentication Manager instance.
     */
    private final AuthenticationManager authenticationManager;

    /**
     * User Repository instance.
     */
    private final UserRepository userRepository;

    /**
     * JWTUtils Instance.
     */
    private JWTTokenUtils jwtTokenUtils;

    /**
     * Plan Service instance.
     */
    private PlanService planService;

    @Autowired
    public UserService(AuthenticationManager authenticationManager, UserRepository userRepository,
                       JWTTokenUtils jwtTokenUtils, PlanService planService) {
        this.authenticationManager = authenticationManager;
        this.userRepository = userRepository;
        this.jwtTokenUtils = jwtTokenUtils;
        this.planService = planService;
    }

    @Override
    protected GenericRepository getGenericRepository() {
        return userRepository;
    }

    @Override
    protected SearchPredicate<User> getSearchPredicate(String search) {
        return null;
    }

    /* Methods */

    /**
     * Method to login on Coupler API.
     *
     * @param jwtRequestDTO Login request DTO.
     * @return {@link JwtResponseDTO}. JWT Token with all the info.
     * @throws RestRequestException The API can throw an exception if it cannot find necessary data.
     */
    public JwtResponseDTO login(JwtRequestDTO jwtRequestDTO) throws RestRequestException {
        var userPassword = new UsernamePasswordAuthenticationToken(jwtRequestDTO.getEmail(), jwtRequestDTO.getPassword());
        // The error is here!
        var auth = authenticationManager.authenticate(userPassword);
        var token = jwtTokenUtils.generateToken(((User) auth.getPrincipal()).getEmail());
        User user = userRepository.findByEmail(jwtRequestDTO.getEmail())
                .orElseThrow(() -> new RestRequestException(HttpStatus.NOT_FOUND, ErrorIndicator.FIM_ERROR_U01.getMessage()));
        return new JwtResponseDTO(token, user.getId());
    }
}

我没有在我的系统中定义任何其他 AuthenticationManager,当我使用 AuthenticationManager 注释或删除“@Bean”时,它声称我的 UserService 需要一个未提供的 bean,而这个 beam 是 AuthenticationManager。 “RequestFilter”是我的“扩展 OncePerRequestFilter”实现,不要认为问题出在,所以为了保持简单,我将忽略它。

java spring-security

评论


答:

1赞 Steve Riesenberg 10/13/2023 #1

这是一个已知问题。您可以正确发布 Bean 以解决它。有关示例,请参阅此评论、此博客文章此答案5.8 迁移指南AuthenticationManager

请注意,Spring Security 也内置了对 JWT 的支持,因此您可以避免编写自己的过滤器。

评论

0赞 Alfredo Marin 10/13/2023
谢谢!!这帮了大忙!现在我只需要了解如何将“UserDetails user = User.withDefaultPasswordEncoder().username(”user“).password(”password“).roles(”USER“).build();”更改为我从端点接收的数据...?我不知道该怎么做!我会看看,看看我能找到什么!再次感谢!
1赞 Steve Riesenberg 10/14/2023
评论链接包含一个示例。
1赞 Steve Riesenberg 10/14/2023
参考文档中的密码存储也包括示例,博客文章也是如此。您正在寻找 .UserDetailsService
0赞 Alfredo Marin 10/23/2023
嘿,又是我。对不起,我对你提到的例子有点关注,但我找不到它们。寻找“UserDetailsService”,我找到了这个例子(baeldung.com/spring-security-authentication-with-a-database),但没有工作。我正在使用 Spring Data JPA,并且用户(名为 Email not Username 的属性)已经保存在数据库中,我正在编码的这个 RestController 端点是登录名,应该检查电子邮件和密码是否匹配并生成一个令牌,我做对了吗?我应该寻找什么?
1赞 Steve Riesenberg 10/23/2023
@AlfredoMarin 请打开一个新问题,详细说明您正在尝试做什么以及您尝试了什么。评论不是解决问题的最佳场所。