Spring Security @AuthenticationPrincipal null

Spring Security @AuthenticationPrincipal null
JA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około rok
  • Postów:46
0

Hej,

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

Kopiuj
@AuthenticationPrincipal UserPrincipal userPrincipal

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

Kopiuj
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:

Kopiuj
@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:

Kopiuj
 @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

Kopiuj
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

edytowany 1x, ostatnio: jatylkonachwile
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:około 7 godzin
  • Postów:1875
0

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

Btw. po co tam @Transactional?


”Engineering is easy. People are hard.” Bill Coughran
edytowany 1x, ostatnio: Charles_Ray
JA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około rok
  • Postów:46
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:

Kopiuj
plugins {
	id 'org.springframework.boot' version '2.2.5.RELEASE'
	...
	...
}
 
dependecies {
	implementation "org.springframework.boot:spring-boot-starter-security"
}
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
JA
Wiem :D 1. Zrobione, mam UserPrincipal 2. Zrobione, Mam UserService z metodą loadUserByUsername 3. Zrobione, ustawione na mój customowy service 4. Brak profitu, jest null :<
Shalom
No to gdzieś coś nie trybi. Postaw breakpointy i zobacz co. Ale ja myślę, ze ty tym swoim filtrem robisz coś dziwnego, bo to pewnie w ogóle nie idzie przez Spring Security tylko "na boku" i stąd takie efekty. Czemu tego JWT nie masz skonfigurowanego normalnie w Spring Security?
JA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około rok
  • Postów:46
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:

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

Natomiast w konfiguracji dodaje filtr:

Kopiuj
.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:

Kopiuj
final var authenticationToken = new UsernamePasswordAuthenticationToken(new UserPrincipal(username, authorities), null, authorities);
edytowany 4x, ostatnio: jatylkonachwile
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
2

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

Mam na myśli jakieś:

Kopiuj
        @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.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.