Пароли при регистрации и логине 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 шт):
У вас есть бин 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, и всё заработало.
Не уверен, что это поможет решить проблему, но на всякий случай можно попробовать.
Проблема решена и была чертовски тупая. В Spring Security TRACE я увидел, что user disabled.