Пароли при регистрации и логине BCryptPasswordEncoder в Spring Security 6 не сходятся

Всем привет, уже давно решить не могу проблему, много что перечитал, так и не понял. В общем у меня есть форма с регистрацией пользователя (Thymeleaf), данные из нее передаются в контроллер, далее пароль хешируется и данные отправляются в базу через JPA.

НО

Когда я пытаюсь войти у меня не работает авторизация, якобы неверный пароль.

В то же время если захешировать пароль на каком-то сайте и вручную вбить его в базу, то войти потом я смогу войти.

То есть если хеш вбить вручную в базу, то я могу войти. Если пройдет регистрация через мое приложение, то я не смогу зайти.

Хеш с сайта-генератора получается с одной версией алгоритма, а хеш, который генерирует мое приложение с другой версией. Поэтому я не понимаю, как так, если у меня на все приложение используется всего один бин PasswordEncoder.

Хеш с сайта-генератора: $2y$10$/mZ5HhyfMTml2xj0HYEX0uQfFgHDnsdJ3IhX0pReHUTRVSDuoqAPO

Хеш сгенерированный моим приложением: $2a$10$2U3MnmqMomhwWQpju1kuy.muBr7TPivlb.wn7XFilMAPJXlwaPx4.

SecurityConfig

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

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

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/", "/css/**", "/js/**", "/images/**", "/candidate/**", "/setup/**").permitAll()
            .requestMatchers("/chat/**").hasAnyRole("ADMIN","HEAD","USER")
            .requestMatchers("/users/**").hasAnyRole("ADMIN","HEAD")
            .requestMatchers("/admin/**").hasAnyRole("ADMIN")
            .anyRequest().authenticated()
        ).formLogin((form) -> form
            .loginPage("/login")
            .failureUrl("/login?error=true")
            .defaultSuccessUrl("/cards", true)
            .permitAll()
        ).logout((logout) -> logout
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login")
            .deleteCookies("JSESSIONID")
            .invalidateHttpSession(true)
            .clearAuthentication(true)
        )
        .build();
    }

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

}

Контроллер формы регистрации

@Controller
@RequestMapping("/setup")
class SetupController {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostMapping("/create")
    public String setupUser(User user) {
        try {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            userService.save(user);
        } catch(Exception e) {
            System.out.println(e);
            return "redirect:/setup?error=true";
        }
        return "redirect:/login";
    }

}

Ответы (2 шт):

Автор решения: Byb

У вас есть бин authenticationProvider, который использует два других бина - userDetailsService и passwordEncoder - путём явного вызова соответствующих им методов:

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

Попробуйте вместо этого использовать @Autowired-способ:

@Bean
@Autowired
public AuthenticationProvider authenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(userDetailsService);
    provider.setPasswordEncoder(passwordEncoder);
    return authProvider;
}

Однажды у меня возникла проблема, очень похожая на вашу. Я тогда много времени потратил, чтобы понять, в чём ошибка, и в итоге методом научного тыка выяснил, что Spring плохо себя вёл по той причине, что в одном месте я внедрял бин (тоже passwordEncoder) посредством вызова метода, а в другом месте - используя @Autowired.

Тогда я вызов метода заменил на @Autuwired, и всё заработало.

Не уверен, что это поможет решить проблему, но на всякий случай можно попробовать.

→ Ссылка
Автор решения: shalaley

Проблема решена и была чертовски тупая. В Spring Security TRACE я увидел, что user disabled.

→ Ссылка