Spring Security @AuthenticationPrincipal null

0

Hej,

Nowy dzień, nowy problem. Otóż próbuję odebrać w kotrollerze mojego customowego principala obecnie zalogowanego usera poprzez :

@AuthenticationPrincipal UserPrincipal userPrincipal

Problem w tym, że ten principal jest nullem.. ale kiedy już wyciągne usera z conextu poprzez

SecurityContextHolder.getContext().getAuthentication();

To widzę, że są tam dane użytkownika. Nie rozumiem co robie źlę, albo czego mi brakuję żeby korzystać z @AuthenticationPrincipal.
Mój customowy principal wygląda tak:

@Getter
@AllArgsConstructor
public class UserPrincipal implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

W konfiguracji security mam adnotację @EnableWebSecurity oraz korzystam z customowego UserServiceDetails który implementuje UserDetailsService , a metoda ładująca usera wygląda tak:

 @Override
 @Transactional
    public UserPrincipal loadUserByUsername(String username) {
        User user = userRepository.findByUsername(username).orElseThrow(() -> new UserNotFoundException(username));

        Set<GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toSet());

        return new UserPrincipal(
                user.getId(),
                user.getUsername(),
                user.getPassword(),
                authorities);
    }

Mam oczywiście napisany filtr który sprawdza token JWT, oraz ładuje usera do contextu poprzez

SecurityContextHolder.getContext().setAuthentication(authenticationToken);

Prosiłbym o poradę, czy co mogę robić źle. Ewentualnie czy powinienem jakoś inaczej to zrealizować, może w inny sposób operować na tym customowym obiekcie principala ? @Shalom @jarekr000000 @Charles_Ray

0

Czy ja też mogę pomóc? :) jaka wersja Spring Security i Spring Boota?

Btw. po co tam @Transactional?

0
Charles_Ray napisał(a):

Czy ja też mogę pomóc? :) jaka wersja Spring Security i Spring Boota?

Btw. po co tam @Transactional?

Jasne, nie mogłem zapamiętać Twojego nicku :D
@Transactional pozostałość po poprzednim kawałku, zbędne, dzięki za spostrzegawczość.
Co do wersji to gradle wygląda tak:

plugins {
	id 'org.springframework.boot' version '2.2.5.RELEASE'
	...
	...
}
 
dependecies {
	implementation "org.springframework.boot:spring-boot-starter-security"
}
0

Mam oczywiście napisany filtr który sprawdza token JWT, oraz ładuje usera do contextu poprzez

Wat? Wiesz ze takie już istnieją i nie trzeba ich pisać samemu?

Anyway, normalnie robi sie tak:

  1. Robisz własne UserDetails
  2. Robisz swoje UserDetailsService
  3. W WebSecurityConfigurerAdapter konfigirujesz ten userDetailsService w AuthenticationManagerBuilder
  4. Profit!

Pytanie tylko po co tak kombinować? Równie dobrze możesz w kontrolerze dostać normalnego Principala i sobie go tam "przerobić" na coś własnego.

0
Shalom napisał(a):

Mam oczywiście napisany filtr który sprawdza token JWT, oraz ładuje usera do contextu poprzez

Wat? Wiesz ze takie już istnieją i nie trzeba ich pisać samemu?

Anyway, normalnie robi sie tak:

  1. Robisz własne UserDetails
  2. Robisz swoje UserDetailsService
  3. W WebSecurityConfigurerAdapter konfigirujesz ten userDetailsService w AuthenticationManagerBuilder
  4. Profit!

Pytanie tylko po co tak kombinować? Równie dobrze możesz w kontrolerze dostać normalnego Principala i sobie go tam "przerobić" na coś własnego.

Nie mieści mi się komentarzu :D
Hmm, co masz na myśli mówiąc normalnie w Spring Security? Chciałem napisać to od 0 żeby lepiej zrozumieć bebechy, to mój projekt prywatny do nauki, ale do rzeczy to generalnie mam JwtAuthorizationFilter dziedziczący po OncePerRequestFilter i implementuję metodę doFilterInternal w której biore JWT token z nagłówka, rozbieram go i sprawdzam czy sygnatura jest w porządku, wyciągam z niego username i role i robię coś takiego:

final var authenticationToken = new UsernamePasswordAuthenticationToken(username, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);

Natomiast w konfiguracji dodaje filtr:

.addFilterBefore(new JwtAuthorizationFilter(secretKey), UsernamePasswordAuthenticationFilter.class)

**EDIT: **dobra, przy debugowaniu doszedłem w czym był błąd, miałeś rację @Shalom to przez mój filtr, zamiast mojego tokenu wrzucałem do contextu po prostu username i przez to później się typy gryzły i zwracało null. Teraz działa ok
Może komuś się kiedyś przyda, to tak na szybko zmieniłem w filtrze to:

final var authenticationToken = new UsernamePasswordAuthenticationToken(new UserPrincipal(username, authorities), null, authorities);
2

Hmm, co masz na myśli mówiąc normalnie w Spring Security?

Mam na myśli jakieś:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/tutajTylkoZTokenem/**")
                    .authenticated()
                    .and()
                    .oauth2ResourceServer()
                    .jwt();
        }

I cyk, nie trzeba żadnych fitrów ani ręcznego sprawdzania sygnatur.

1 użytkowników online, w tym zalogowanych: 0, gości: 1