Как вручную аутентифицировать пользователя используя Spring Security?
Я отключил страницу аутентификации по умолчанию с целью вручную аутентифицировать пользователя. Моя конфигурация:
@Bean
public SecurityFilterChain filter(HttpSecurity http, SecurityContextRepository securityContextRepository) throws Exception {
return http
.addFilterAfter(new CsrfTokenLogger(), CsrfFilter.class)
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/", "/home", "/login", "/register").permitAll()
.requestMatchers(HttpMethod.POST, "/login", "/register").permitAll()
.requestMatchers("/user").hasAnyAuthority("USER", "ADMIN")
.requestMatchers("/admin").hasAnyAuthority("ADMIN")
.anyRequest().authenticated()
)
.formLogin((form) -> form.disable()) // using custom login system
.logout((logout) -> logout.permitAll())
.securityContext(securityContext -> securityContext.securityContextRepository(securityContextRepository))
.build();
}
Мой контроллер, который аутентифицирует пользователя:
@PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String loginUser(@RequestBody MultiValueMap<String, String> formData, HttpServletRequest request, HttpServletResponse response, Model model) {
logger.info("LOGIN USER");
String username = formData.getFirst("username");
String password = formData.getFirst("password");
Authentication formAuth = new UsernamePasswordAuthenticationToken(username, password);
logger.info("AUTHENTICATE");
Authentication authentication = authenticationManager.authenticate(formAuth);
logger.info("AUTHENTICATED");
if (!authentication.isAuthenticated()) {
model.addAttribute("incorrectUsernameOrPassword", true);
return "login";
}
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(authentication);
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, request, response);
return "login";
}
Если на странице логина ввести правильные данные пользователя, то всё будет ОК, но если ввести неправильные данные, то будет показана ошибка 403, хотя по идее должна показываться та же страница с сообщением о том, что введены неправильные данные пользователя.
Аутентифицирует пользователя строка authenticationManager.authenticate(formAuth);, и, если ввести неправильные данные, программа дальше не проходит и показывается ошибка 403.
Ответы (1 шт):
Чтобы обрабатывать редиректы по-разному в зависимости от аутентификации, нужно настроить обработку чернз AuthenticationFailureHandler:
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Устанавливаем нужный HTTP статус
response.sendRedirect("/login?error=true"); // Редирект на страницу логина с параметром ошибки
}
}
//конфигурация Security
http
.addFilterAfter(new CsrfTokenLogger(), CsrfFilter.class)
.authorizeRequests((requests) -> requests
.requestMatchers("/", "/home", "/login", "/register").permitAll()
.requestMatchers(HttpMethod.POST, "/login", "/register").permitAll()
.requestMatchers("/user").hasAnyAuthority("USER", "ADMIN")
.requestMatchers("/admin").hasAnyAuthority("ADMIN")
.anyRequest().authenticated()
)
.formLogin((form) -> form.disable())
.logout((logout) -> logout.permitAll())
.securityContext(securityContext -> securityContext.securityContextRepository(securityContextRepository))
.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.csrf().disable()
.formLogin().loginPage("/login").failureHandler(new MyAuthenticationFailureHandler())
.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();