Как вручную аутентифицировать пользователя используя 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 шт):

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

Чтобы обрабатывать редиректы по-разному в зависимости от аутентификации, нужно настроить обработку чернз 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();
→ Ссылка