WebFlux ServerRequest attributes jako przechowywalnia info o użytkowniku

0

Mam serwis WebFluxowy oparty na Spring Boot 2.1.x, Netty.
Serwis exposuje kilka REST endpointów, które wymagają, żeby użytkownik był authenticated/authorized.
W tym celu każdy ServerRequest przechodzi przez funkcję filtrującą, która sprawdza, czy JWT token jest obecny w ciasteczku, i czy da się go sparsować.
Przy okazji parsowania, chciałbym informacje gdzieś zapisać do ponownego użytku przez kolejne funkcje (np. handler, który do wykonania potrzebuje nazwy użytkownika albo użytkownika, który ma jakąś rolę)

Tą informacją byłby jakiś mój obiekt, np. AuthInfo(String username, List<string> roles)

Najoczywistszym miejscem do zachowania tej informacji wydaje się dla mnie być pole "attributes" ServerRequestu, i tak też robię.

Pytanie brzmi; czy dobrze robię?

0

PS. Chodzi dokładnie o ten ServerRequest, i to pole:
https://docs.spring.io/spring[...]rverRequest.html#attributes--

0

Jakbyś robił w funkcyjnym webflux to będzie proste.
Handler to funkcja z Request do Respose.
Można napisać taką funkcję (np :doAuthenticated), która jako argument przyjmuje funkcję od AuthInfo, Request -> Response a zwraca Handler czyli Request -> Response.
W tym doAuthenticated możesz powyciągać co trzeba z requesta i przekazywać już wyciągniete do właściwej funkcji.

Pakowanie rzeczy w Request Attributes i generalnie targanie tego request przez następne warstwy to rak. Choć tak się kiedyś robiło.

0

Dzięki @jarekr000000 za odpowiedź. Zrefaktoruję... zobaczymy. Przy okazji będę się musiał pozbyć aspektu, o którym nie wspomniałem @RequiresRole("RAK") ]:->

0

Borykam się z tym samym problemem, tylko ja nie do końca rozumiem odpowiedź @jarekr000000 :P

Mam taki endpoint pobierania tasków

    private HandlerFunction<ServerResponse> getTasks() {
        return request -> {
            log.debug("pobieramy wszystkie taski");
            final List<Task> allTasks = service.findAllTasks();
            return ServerResponse.ok().body(fromObject(allTasks.toJavaList()));
        };
    }

Teraz chciałbym dodać security i pobierać taski tylko aktualnie zalogowanego użytkownika. Używam JWT. Napisałem sobie AuthenticationManager implements ReactiveAuthenticationManager, w którym nadpisuję metodę authenticate, w której sobie waliduję token JWT i jak wszystko ok to zwracam UsernamePasswordAuthenticationToken z moim userem i jego rolami.

Jak się dobrać do tego usera w endpoincie getTasks() ?

request.principal() i ReactiveSecurityContextHolder.getContext() zwracają mi puste wartości.

Wiem, że w getTasks() mogę dobrać się z requesta do headerów -> tokena -> sparsować go jeszcze raz i pobrać sobie użytkownika, ale parsowanie tokenu w dwóch miejscach za każdym requestem użytkownika to nie jest najlepsza droga.

1

Nie podpowiem odnośnie security, ale IMO metoda findAllTasks() powinna przyjmować jako Stringa username i nie wiedzieć nic o warstwie web :P

0

@scibi92: i właśnie tak zrobię. W filtrach spring security będę walidował token i puszczał lub nie dalej request. W metodach routera, tak jak powyższy getTasks(), będę wyciągał tylko username z tokenu (lub budował sobie obiekt AuthInfo tak jak autor wątku napisał) i przekazywał go do serwisu np. jako parametr metody findAllTasks().
Podwójna walidacja tokena nie ma sensu, bo kod metody routera i tak nie wykona się, jeśli walidacja w filtrach się nie powiedzie.

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