Не могу понять, почему мой логинконтроллер не может аутентифицировать пользователя. Spring Security сводит меня с ума

Внес много правок. Раньше не устанавливал контекст Springsecurity. Это ошибка, которую я получаю:

2024-07-05T02:37:01.443-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] estMatcherDelegatingAuthorizationManager : Checking authorization on POST /login_success using AuthorityAuthorizationManager[authorities=[USER]]
2024-07-05T02:37:01.443-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] w.c.HttpSessionSecurityContextRepository : Did not find SecurityContext in HttpSession 78D83992116FD8443A13A27376BEA891 using the SPRING_SECURITY_CONTEXT session attribute
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=78D83992116FD8443A13A27376BEA891], Granted Authorities=[ROLE_ANONYMOUS]]
2024-07-05T02:37:01.444-04:00 TRACE 46690 --- [fitBuddyApp] [nio-8080-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=78D83992116FD8443A13A27376BEA891], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access Denied

Это мои данные пользователя через CustomUserDetails.

public class CustomUserDetails implements UserDetails {

    private User user;
    private int id;

    private String username;

    Role user_role;

    private String email;

    @JsonIgnore
    private String password;

    private Collection<? extends GrantedAuthority> authorities;

    public CustomUserDetails(User user) {

    }


    public CustomUserDetails(int id, String getusername, String role, String password, String email, List<GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.user_role = Role.valueOf("USER");
        this.password = password;
        this.authorities = authorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        SimpleGrantedAuthority authority = new SimpleGrantedAuthority(user.getRoles().toString());
        return Arrays.asList(authority);
    }

    public String getPassword() {
        return user.getPassword();
    }

    public String getUsername() {
        return user.getusername();
    }

    public boolean isAccountNonExpired() {
        return true;
    }

    public boolean isAccountNonLocked() {
        return true;
    }

    public boolean isCredentialsNonExpired() {
        return true;
    }

    public boolean isEnabled() {
        return true;
    }

Это мой CustomUserDetailsService.

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new org.springframework.security.core.userdetails.User(user.getusername(), user.getPassword(), getAuthorities(user));
    }

    private Collection<? extends GrantedAuthority> getAuthorities(User user) {
        List<GrantedAuthority> authorities = new ArrayList<>();
        // Example: Fetching user roles and converting them to GrantedAuthority
        user.getRoles().forEach(role -> {
            authorities.add(new SimpleGrantedAuthority("USER"));
        });
        return authorities;
    }

This is my loginController. I'm trying to implement securityContext.

@Контроллер публичный класс loginController {

private final AuthenticationManager authenticationManager;

private final SecurityContextHolderStrategy securityContextHolderStrategy =
        SecurityContextHolder.getContextHolderStrategy();

private final SecurityContextRepository securityContextRepository =
        new HttpSessionSecurityContextRepository();

private HttpServletRequest request;
private HttpServletResponse response;

PasswordEncoder bcrypt = new BCryptPasswordEncoder();

UserRepository userRepository;


public loginController(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

@RequestMapping("/login")
public String login(Model model) {
    return "login";
}


@PostMapping("/login_success")
public String processLogin(@RequestParam String username, @RequestParam String password,
HttpServletRequest request, HttpServletResponse response) {


    List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("USER");
    User user = new User();
    user.setusername(username);
    userRepository.findByUsername(username);
    user.setPassword(password);


    UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.authenticated(
            username, password, authorities);

    authenticationManager.authenticate(token);

    SecurityContext securityContext = this.securityContextHolderStrategy.createEmptyContext();
    securityContext.setAuthentication(token);
    this.securityContextHolderStrategy.setContext(securityContext);
    this.securityContextRepository.saveContext(securityContext, request, response);

    return "redirect:/login_success";
}

И вот моя конфигурация безопасности:

@EnableWebSecurity // have to add or it can't find HttpSecurity type
@Configuration
public class SecurityConfig {


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {



        http
                .csrf(Customizer.withDefaults())
                .authorizeHttpRequests((requests) -> requests
                        .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
                        .requestMatchers("/", "/home", "/confirmation").permitAll()
                        .requestMatchers("/signup").permitAll()
                        .requestMatchers("/login").permitAll()
                        .requestMatchers("/css/**").permitAll()
                        .requestMatchers("/login_success").hasAuthority("USER").anyRequest().authenticated()


                )

                .securityContext((securityContext) -> securityContext
                        .requireExplicitSave(true)
                )


                .formLogin(form ->
                        form
                                .loginPage("/login")
                                .usernameParameter("username")
                                .passwordParameter("password")
                                .loginProcessingUrl("/login")
                                .defaultSuccessUrl("/login_success")
                                .permitAll()

                )
                .logout(l -> l
                        .logoutSuccessUrl("/").permitAll()


                );

        return http.build();
    }

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

    @Bean
    public AuthenticationManager authenticationManager(UserDetailsService customUserDetailsService,
                                                       PasswordEncoder encoder) {

        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();

        authenticationProvider.setUserDetailsService(customUserDetailsService);
        authenticationProvider.setPasswordEncoder(encoder);

        return new ProviderManager(authenticationProvider);
    }

Лучше ли реализовать держателя контекста безопасности в конфигурации безопасности?

Следую этим документам и, похоже, не могу найти руководства по использованию пользовательской точки входа в систему для весны 6.1+.

https://docs.spring.io/spring-security/reference/6.1/migration/servlet/session-management.html

https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-authenticationprovider

https://docs.spring.io/spring-security/reference/servlet/authentication/persistence.html#httpsecuritycontextrepository

После аутентификации (поскольку вы решили написать собственную конечную точку входа) вам необходимо сохранить объект аутентификации в SecurityContext. Это описано в главе «Архитектура аутентификации».

Toerktumlare 03.07.2024 07:35

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

Toerktumlare 04.07.2024 09:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

ваши конструкторы в классе CustomUserDetails кажутся неверными. Вы принимаете значения в параметризованном конструкторе, но тело пусто, которое вы также вызываете из функции сборки, а ваш непараметризованный конструктор устанавливает значения, но не имеет никаких параметров, поэтому они задаются сами.

исправьте их так:

    public CustomUserDetails( ) {
        
    }
    
    public CustomUserDetails(int id, String getusername, String role, String password, String email, List<GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.role = role;
        this.password = password;
        this.authorities = authorities;
    }

Ответ принят как подходящий

Я внес изменения в конфигурацию входа в систему

public class loginController {

    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

и конфигурация безопасности

 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {


        http
                .csrf().disable()
                .authorizeHttpRequests((requests) -> requests
                        .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
                        .requestMatchers("/", "/home", "/confirmation").permitAll()
                        .requestMatchers("/signup").permitAll()
                        .requestMatchers("/login").permitAll()
                        .requestMatchers("/css/**").permitAll()
                        .requestMatchers("/profile").permitAll()
                )

                .formLogin(form->
                        form
                                .loginPage("/login")
                                .loginProcessingUrl("/processlogin")
                                .defaultSuccessUrl("/profile")
                                .permitAll()


                )
                .logout(l -> l
                        .logoutSuccessUrl("/logout").invalidateHttpSession(true)

Работает сейчас.

Другие вопросы по теме