Jak działa łańcuch filtrów Spring Security

145

Zdaję sobie sprawę, że zabezpieczenia Spring zbudowane są na łańcuchu filtrów, które przechwytują żądanie, wykryją (brak) uwierzytelnienia, przekierowują do punktu wejścia uwierzytelniania lub przekazują żądanie do usługi autoryzacji i ostatecznie pozwalają żądaniu trafić do serwletu lub zgłosić wyjątek bezpieczeństwa (nieuwierzytelnione lub nieautoryzowane). DelegatingFitlerProxy skleja te filtry razem. Aby wykonywać swoje zadania, filtrują usługi dostępu, takie jak UserDetailsService i AuthenticationManager .

Kluczowe filtry w łańcuchu to (w kolejności)

  • SecurityContextPersistenceFilter (przywraca uwierzytelnianie z JSESSIONID)
  • UsernamePasswordAuthenticationFilter (przeprowadza uwierzytelnianie)
  • ExceptionTranslationFilter (przechwytywanie wyjątków bezpieczeństwa z FilterSecurityInterceptor)
  • FilterSecurityInterceptor (może generować wyjątki uwierzytelniania i autoryzacji)

Nie wiem, jak są używane te filtry. Czy chodzi o to, że w przypadku logowania formularza dostarczonego przez wiosnę, UsernamePasswordAuthenticationFilter jest używany tylko do / login , a ostatnie filtry nie? Czy element przestrzeni nazw logowania do formularza automatycznie konfiguruje te filtry? Czy każde żądanie (uwierzytelnione lub nie) dociera do FilterSecurityInterceptor w przypadku adresu URL bez logowania?

A jeśli chcę zabezpieczyć REST API tokenem JWT , który jest pobierany z loginu? Muszę skonfigurować dwa httpznaczniki konfiguracji przestrzeni nazw , prawa? Jeden dla / login with UsernamePasswordAuthenticationFilter, a drugi dla adresów URL REST, z niestandardowym JwtAuthenticationFilter.

Czy konfiguracja dwóch httpelementów tworzy dwa springSecurityFitlerChains? UsernamePasswordAuthenticationFilterDomyślnie jest wyłączone, dopóki nie zadeklaruję form-login? Jak wymienić SecurityContextPersistenceFilterna filtr, który otrzyma Authenticationz istniejącego, JWT-tokena nie JSESSIONID?

Tuomas Toivonen
źródło
Domyślna kolejność filtrów jest zdefiniowana w org.springframework.security.config.annotation.web.builders.FilterComparator
blacelle

Odpowiedzi:

221

Łańcuch filtrów zabezpieczających Spring to bardzo złożony i elastyczny silnik.

Kluczowe filtry w łańcuchu to (w kolejności)

  • SecurityContextPersistenceFilter (przywraca uwierzytelnianie z JSESSIONID)
  • UsernamePasswordAuthenticationFilter (przeprowadza uwierzytelnianie)
  • ExceptionTranslationFilter (przechwytywanie wyjątków bezpieczeństwa z FilterSecurityInterceptor)
  • FilterSecurityInterceptor (może generować wyjątki uwierzytelniania i autoryzacji)

Patrząc na aktualną dokumentację stabilnej wersji 4.2.1 , w sekcji 13.3 Zamawianie filtrów , można zobaczyć całą organizację filtrów w łańcuchu filtrów:

13.3 Zamawianie filtrów

Kolejność definiowania filtrów w łańcuchu jest bardzo ważna. Niezależnie od tego, z jakich filtrów faktycznie korzystasz, kolejność powinna wyglądać następująco:

  1. ChannelProcessingFilter , ponieważ może być konieczne przekierowanie do innego protokołu

  2. SecurityContextPersistenceFilter , więc SecurityContext można skonfigurować w SecurityContextHolder na początku żądania internetowego, a wszelkie zmiany w SecurityContext można skopiować do HttpSession po zakończeniu żądania internetowego (gotowe do użycia z następnym żądaniem sieci Web)

  3. ConcurrentSessionFilter , ponieważ używa funkcji SecurityContextHolder i musi zaktualizować SessionRegistry, aby odzwierciedlić bieżące żądania od jednostki głównej

  4. Mechanizmy przetwarzania uwierzytelniania - UsernamePasswordAuthenticationFilter , CasAuthenticationFilter , BasicAuthenticationFilter itp. - aby element SecurityContextHolder mógł zostać zmodyfikowany tak, aby zawierał prawidłowy token żądania uwierzytelnienia

  5. SecurityContextHolderAwareRequestFilter , jeśli używasz go zainstalować Wiosna Bezpieczeństwa świadomy HttpServletRequestWrapper do kontenera serwletów

  6. JaasApiIntegrationFilter , jeśli JaasAuthenticationToken jest w SecurityContextHolder będzie przetwarzać filterChain jako przedmiot w JaasAuthenticationToken

  7. RememberMeAuthenticationFilter , aby jeśli żaden wcześniejszy mechanizm przetwarzania uwierzytelniania nie zaktualizował SecurityContextHolder, a żądanie przedstawia plik cookie umożliwiający działanie usług zapamiętaj mnie, zostanie tam umieszczony odpowiedni zapamiętany obiekt uwierzytelniania

  8. AnonymousAuthenticationFilter , więc jeśli żaden wcześniejszy mechanizm przetwarzania uwierzytelniania nie zaktualizował SecurityContextHolder, zostanie tam umieszczony obiekt anonimowego uwierzytelniania

  9. ExceptionTranslationFilter , aby złapać wszelkie wyjątki Spring Security, aby można było zwrócić odpowiedź błędu HTTP lub uruchomić odpowiedni AuthenticationEntryPoint

  10. FilterSecurityInterceptor , aby chronić identyfikatory URI sieci Web i zgłaszać wyjątki w przypadku odmowy dostępu

Teraz spróbuję przejść do kolejnych pytań, jedno po drugim:

Nie wiem, jak są używane te filtry. Czy chodzi o to, że w przypadku logowania formularza dostarczonego przez wiosnę, UsernamePasswordAuthenticationFilter jest używany tylko do / login, a ostatnie filtry nie? Czy element przestrzeni nazw logowania do formularza automatycznie konfiguruje te filtry? Czy każde żądanie (uwierzytelnione lub nie) dociera do FilterSecurityInterceptor w przypadku adresu URL bez logowania?

Po skonfigurowaniu <security-http>sekcji dla każdej z nich musisz podać przynajmniej jeden mechanizm uwierzytelniania. To musi być jeden z filtrów pasujących do grupy 4 w sekcji 13.3 Zamawianie filtrów z dokumentacji Spring Security, do której właśnie się odwołałem.

Oto minimalne obowiązujące zabezpieczenia: element http, który można skonfigurować:

<security:http authentication-manager-ref="mainAuthenticationManager" 
               entry-point-ref="serviceAccessDeniedHandler">
    <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
</security:http>

Robiąc to, te filtry są konfigurowane w proxy łańcucha filtrów:

{
        "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
        "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
        "3": "org.springframework.security.web.header.HeaderWriterFilter",
        "4": "org.springframework.security.web.csrf.CsrfFilter",
        "5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
        "6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
        "7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
        "8": "org.springframework.security.web.session.SessionManagementFilter",
        "9": "org.springframework.security.web.access.ExceptionTranslationFilter",
        "10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
    }

Uwaga: otrzymuję je, tworząc prosty RestController, który @Autowires the FilterChainProxy i zwraca jego zawartość:

    @Autowired
    private FilterChainProxy filterChainProxy;

    @Override
    @RequestMapping("/filterChain")
    public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
        return this.getSecurityFilterChainProxy();
    }

    public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
        Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>();
        int i = 1;
        for(SecurityFilterChain secfc :  this.filterChainProxy.getFilterChains()){
            //filters.put(i++, secfc.getClass().getName());
            Map<Integer, String> filters = new HashMap<Integer, String>();
            int j = 1;
            for(Filter filter : secfc.getFilters()){
                filters.put(j++, filter.getClass().getName());
            }
            filterChains.put(i++, filters);
        }
        return filterChains;
    }

Tutaj mogliśmy zobaczyć, że po prostu deklarując <security:http>element z jedną minimalną konfiguracją, wszystkie domyślne filtry są uwzględnione, ale żaden z nich nie jest typu uwierzytelniania (czwarta grupa w sekcji 13.3 Kolejność filtrów). Oznacza to więc, że po prostu zadeklarowanie security:httpelementu, SecurityContextPersistenceFilter, ExceptionTranslationFilter i FilterSecurityInterceptor są automatycznie konfigurowane.

W rzeczywistości jeden mechanizm przetwarzania uwierzytelniania powinien być skonfigurowany, a nawet ziarna bezpieczeństwa przestrzeni nazw przetwarzają oświadczenia o tym, zgłaszając błąd podczas uruchamiania, ale można to ominąć dodając atrybut punktu wejścia w <http:security>

Jeśli dodam <form-login>do konfiguracji basic to w ten sposób:

<security:http authentication-manager-ref="mainAuthenticationManager">
    <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
    <security:form-login />
</security:http>

Teraz filterChain będzie wyglądał tak:

{
        "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
        "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
        "3": "org.springframework.security.web.header.HeaderWriterFilter",
        "4": "org.springframework.security.web.csrf.CsrfFilter",
        "5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter",
        "6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter",
        "7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
        "8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
        "9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
        "10": "org.springframework.security.web.session.SessionManagementFilter",
        "11": "org.springframework.security.web.access.ExceptionTranslationFilter",
        "12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
    }

Teraz te dwa filtry org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter i org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter są tworzone i konfigurowane w FilterChainProxy.

A więc teraz pytania:

Czy chodzi o to, że w przypadku logowania formularza dostarczonego przez wiosnę, UsernamePasswordAuthenticationFilter jest używany tylko do / login, a ostatnie filtry nie?

Tak, jest używany do próby zakończenia mechanizmu przetwarzania logowania w przypadku, gdy żądanie jest zgodne z adresem URL UsernamePasswordAuthenticationFilter. Ten adres URL można skonfigurować lub nawet zmienić jego zachowanie, aby pasowało do każdego żądania.

Możesz także mieć więcej niż jeden mechanizm przetwarzania uwierzytelniania skonfigurowany w tym samym FilterchainProxy (na przykład HttpBasic, CAS itp.).

Czy element przestrzeni nazw logowania do formularza automatycznie konfiguruje te filtry?

Nie, element form-login konfiguruje UsernamePasswordAUthenticationFilter, a jeśli nie podasz adresu URL strony logowania, konfiguruje również org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, który kończy się prostym automatycznie wygenerowanym loginem strona.

Pozostałe filtry są domyślnie automatycznie konfigurowane przez utworzenie <security:http>elementu bez security:"none"atrybutu.

Czy każde żądanie (uwierzytelnione lub nie) dociera do FilterSecurityInterceptor w przypadku adresu URL bez logowania?

Każde żądanie powinno do niego dotrzeć, gdyż jest to element, który dba o to, czy żądanie ma prawo dotrzeć do żądanego adresu URL. Ale niektóre z filtrów przetworzonych wcześniej mogą zatrzymać przetwarzanie łańcucha filtrów po prostu nie wywołując FilterChain.doFilter(request, response);. Na przykład filtr CSRF może zatrzymać przetwarzanie łańcucha filtrów, jeśli żądanie nie ma parametru csrf.

Co zrobić, jeśli chcę zabezpieczyć REST API tokenem JWT, który jest pobierany z loginu? Muszę skonfigurować dwa znaczniki http konfiguracji przestrzeni nazw, prawa? Inny dla / login with UsernamePasswordAuthenticationFilter, a drugi dla adresów URL REST, z niestandardowym JwtAuthenticationFilter.

Nie, nie jesteś do tego zmuszony. Możesz zadeklarować oba UsernamePasswordAuthenticationFilteri the JwtAuthenticationFilterw tym samym elemencie http, ale zależy to od konkretnego zachowania każdego z tych filtrów. Oba podejścia są możliwe i ostatecznie wybór zależy od własnych preferencji.

Czy skonfigurowanie dwóch elementów http powoduje utworzenie dwóch springSecurityFitlerChains?

Tak to prawda

Czy UsernamePasswordAuthenticationFilter jest domyślnie wyłączony, dopóki nie zadeklaruję logowania przez formularz?

Tak, możesz to zobaczyć w filtrach podniesionych w każdej z opublikowanych przeze mnie konfiguracji

Jak zamienić SecurityContextPersistenceFilter na taki, który uzyska uwierzytelnienie z istniejącego tokenu JWT zamiast JSESSIONID?

Możesz uniknąć SecurityContextPersistenceFilter, po prostu skonfiguruj strategię sesji w <http:element>. Po prostu skonfiguruj w ten sposób:

<security:http create-session="stateless" >

Lub w tym przypadku możesz nadpisać go innym filtrem, w ten sposób wewnątrz <security:http>elementu:

<security:http ...>  
   <security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/>    
</security:http>
<beans:bean id="myCustomFilter" class="com.xyz.myFilter" />

EDYTOWAĆ:

Jedno pytanie o „Ty też możesz mieć więcej niż jeden mechanizm przetwarzania uwierzytelniania skonfigurowany w tym samym FilterchainProxy”. Czy ta ostatnia nadpisze uwierzytelnienie przeprowadzone przez pierwsze, jeśli deklaruje się wiele filtrów uwierzytelniania (implementacja Spring)? Jak to się ma do posiadania wielu dostawców uwierzytelniania?

Ostatecznie zależy to od implementacji samego każdego filtru, ale prawdą jest, że te ostatnie filtry uwierzytelniania są w stanie przynajmniej nadpisać wszelkie wcześniejsze uwierzytelnienia, które ostatecznie zostały wykonane przez poprzednie filtry.

Ale to niekoniecznie się stanie. Mam pewne przypadki produkcyjne w zabezpieczonych usługach REST, w których używam pewnego rodzaju tokenu autoryzacyjnego, który można podać zarówno jako nagłówek HTTP, jak i wewnątrz treści żądania. Więc konfiguruję dwa filtry, które odzyskują ten token, w jednym przypadku z nagłówka HTTP, a drugi z treści żądania własnego żądania odpoczynku. Prawdą jest, że jeśli jedno żądanie HTTP zawiera ten token uwierzytelniania zarówno jako nagłówek HTTP, jak i wewnątrz treści żądania, oba filtry będą próbowały wykonać mechanizm uwierzytelniania delegując go do menedżera, ale można go łatwo uniknąć, po prostu sprawdzając, czy żądanie jest już uwierzytelniony na początku doFilter()metody każdego filtra.

Posiadanie więcej niż jednego filtru uwierzytelniania wiąże się z posiadaniem więcej niż jednego dostawcy uwierzytelniania, ale nie wymuszaj tego. W przypadku ujawnienia wcześniej mam dwa filtry uwierzytelniania, ale mam tylko jednego dostawcę uwierzytelniania, ponieważ oba filtry tworzą ten sam typ obiektu uwierzytelniania, więc w obu przypadkach menedżer uwierzytelniania deleguje go do tego samego dostawcy.

I przeciwnie, ja też mam scenariusz, w którym publikuję tylko jeden UsernamePasswordAuthenticationFilter, ale poświadczenia użytkownika oba mogą być zawarte w DB lub LDAP, więc mam dwóch dostawców obsługujących UsernamePasswordAuthenticationToken, a AuthenticationManager deleguje każdą próbę uwierzytelnienia z filtru do dostawców w celu potwierdzenia poświadczeń.

Myślę więc, że jest jasne, że ani liczba filtrów uwierzytelniania nie określa liczby dostawców uwierzytelniania, ani liczba dostawców nie determinuje liczby filtrów.

Ponadto dokumentacja stwierdza, że ​​SecurityContextPersistenceFilter jest odpowiedzialny za czyszczenie SecurityContext, co jest ważne ze względu na buforowanie wątków. Jeśli go pominę lub wykonam niestandardową implementację, muszę wykonać czyszczenie ręcznie, prawda? Czy istnieje więcej podobnych problemów podczas dostosowywania łańcucha?

Wcześniej nie przyglądałem się dokładnie temu filtrowi, ale po Twoim ostatnim pytaniu sprawdzałem jego implementację i jak zwykle w Spring prawie wszystko można było skonfigurować, rozszerzyć lub nadpisać.

W SecurityContextPersistenceFilter delegaci w SecurityContextRepository realizacji poszukiwanie SecurityContext. Domyślnie używany jest HttpSessionSecurityContextRepository , ale można to zmienić za pomocą jednego z konstruktorów filtru. Więc może być lepiej napisać SecurityContextRepository, który pasuje do twoich potrzeb i po prostu skonfigurować go w SecurityContextPersistenceFilter, ufając jego sprawdzonemu zachowaniu, zamiast zaczynać wszystko od zera.

jlumietu
źródło
3
To było pouczające wyjaśnienie. Jedno pytanie o „Ty też możesz mieć więcej niż jeden mechanizm przetwarzania uwierzytelniania skonfigurowany w tym samym FilterchainProxy”. Czy ta ostatnia nadpisze uwierzytelnienie przeprowadzone przez pierwsze, jeśli deklaruje się wiele filtrów uwierzytelniania (implementacja Spring)? Jak to się ma do posiadania wielu dostawców uwierzytelniania?
Tuomas Toivonen
Ponadto dokumentacja stwierdza, że ​​SecurityContextPersistenceFilter jest odpowiedzialny za czyszczenie SecurityContext, co jest ważne ze względu na buforowanie wątków. Jeśli go pominę lub wykonam niestandardową implementację, muszę wykonać czyszczenie ręcznie, prawda? Czy istnieje więcej podobnych problemów podczas dostosowywania łańcucha?
Tuomas Toivonen,
1
@TuomasToivonen Zredagowałem odpowiedź po pytaniach w twoich ostatnich komentarzach
jlumietu
1
@jlumietu Brakuje cudzysłowu w adnotacji java obok ("/ filterChain) . Również gdzie umieszczasz tę metodę? Próbowałem dodać ją w kontrolerze i mam:No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Dimitri Kopriwa
@BigDong upewnij się, że zadeklarowałeś SpringSecurityFilterChain w konfiguracji web.xml lub java webapp oraz w konfiguracji wiosennej. Ten fragment kodu musi być zawarty w kontrolerze, tak jak zrobiłeś to. I tak, masz rację co do brakującego cytatu
jlumietu
8

Spring security to framework oparty na filtrach, który umieszcza WALL (HttpFireWall) przed twoją aplikacją w postaci filtrów proxy lub fasoli zarządzanych przez sprężynę. Twoje żądanie musi przejść przez wiele filtrów, aby dotrzeć do interfejsu API.

Sekwencja wykonania w Spring Security

  1. WebAsyncManagerIntegrationFilter Zapewnia integrację między SecurityContext i WebAsyncManager Spring Web.

  2. SecurityContextPersistenceFilterTen filtr będzie wykonywany tylko raz na żądanie, wypełnia SecurityContextHolder informacjami uzyskanymi ze skonfigurowanego SecurityContextRepository przed żądaniem i zapisuje je z powrotem w repozytorium po zakończeniu żądania i wyczyszczeniu kontekstu.
    Żądanie jest sprawdzane pod kątem istniejącej sesji. Jeśli nowe żądanie, SecurityContext zostanie utworzone, w przeciwnym razie, jeśli żądanie ma sesję, wówczas istniejący kontekst zabezpieczeń zostanie pobrany z repozytorium .

  3. HeaderWriterFilter Filtruj implementację, aby dodać nagłówki do bieżącej odpowiedzi.

  4. LogoutFilterJeśli adres URL żądania to /logout(dla konfiguracji domyślnej) lub jeśli matematyka adresu URL żądania RequestMatcherskonfigurowana w LogoutConfigurerto

    • czyści kontekst bezpieczeństwa.
    • unieważnia sesję
    • usuwa wszystkie pliki cookie z nazwami plików cookie skonfigurowanymi w LogoutConfigurer
    • Przekierowuje do domyślnego /skonfigurowanego adresu URL pomyślnego wylogowania lub adresu URL pomyślnego wylogowania albo wywołuje skonfigurowany logoutSuccessHandler.
  5. UsernamePasswordAuthenticationFilter

    • Dla każdego adresu URL żądania innego niż loginProcessingUrl ten filtr nie będzie przetwarzał dalej, ale łańcuch filtrów będzie kontynuowany.
    • Jeśli żądany adres URL jest zgodny (musi być HTTP POST) domyślny /loginlub pasuje .loginProcessingUrl()skonfigurowany w, FormLoginConfigurerwówczas UsernamePasswordAuthenticationFilterpróbuje uwierzytelnić.
    • Domyślne parametry formularza logowania są nazwa użytkownika i hasło, może być zastąpione przez usernameParameter(String), passwordParameter(String).
    • ustawienie .loginPage() zastępuje wartości domyślne
    • Podczas próby uwierzytelnienia
      • Authenticationprzedmiot ( UsernamePasswordAuthenticationTokenlub dowolny realizacja Authenticationjest tworzony w przypadku niestandardowego filtra auth).
      • i authenticationManager.authenticate(authToken)zostanie wywołany
      • Zauważ, że możemy skonfigurować dowolną liczbę AuthenticationProvidermetod uwierzytelniania, próbujących wszystkich dostawców uwierzytelniania i sprawdzających dowolny supportsobiekt authToken / uwierzytelniania dostawcy uwierzytelniania, obsługujący dostawcę uwierzytelniania będzie używany do uwierzytelniania. i zwraca obiekt uwierzytelniania w przypadku pomyślnego uwierzytelnienia, które rzuca else AuthenticationException.
    • Jeśli sesja uwierzytelniania zostanie utworzona i authenticationSuccessHandlerzostanie wywołana, która przekierowuje do skonfigurowanego docelowego adresu URL (domyślnie /)
    • Jeśli uwierzytelnianie nie powiodło się, użytkownik staje się nieuwierzytelnionym użytkownikiem, a łańcuch jest kontynuowany.
  6. SecurityContextHolderAwareRequestFilter, jeśli używasz go do instalowania HttpServletRequestWrapper obsługującego Spring Security w kontenerze serwletów

  7. AnonymousAuthenticationFilterWykrywa, czy w SecurityContextHolder nie ma obiektu uwierzytelniania, jeśli nie znaleziono obiektu uwierzytelniania, tworzy Authenticationobiekt ( AnonymousAuthenticationToken) z przyznanymi uprawnieniami ROLE_ANONYMOUS. Tutaj AnonymousAuthenticationTokenułatwia identyfikację kolejnych żądań nieuwierzytelnionych użytkowników.

Dzienniki debugowania
DEBUG - /app/admin/app-config at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@aeef7b36: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 
  1. ExceptionTranslationFilter, aby złapać wszelkie wyjątki Spring Security, aby można było zwrócić odpowiedź błędu HTTP lub uruchomić odpowiedni AuthenticationEntryPoint

  2. FilterSecurityInterceptor
    Pojawi się ten, FilterSecurityInterceptorktóry jest prawie ostatni w łańcuchu filtrów, który pobiera obiekt uwierzytelniania z SecurityContexti otrzymuje listę przyznanych uprawnień (przyznane role) i podejmie decyzję, czy zezwolić temu żądaniu na dotarcie do żądanego zasobu, czy nie, decyzja jest podejmowana przez dopasowanie z dozwolone AntMatchersskonfigurowane w HttpSecurityConfiguration.

Rozważ wyjątki 401-UnAuthorized i 403-Forbidden. Te decyzje zostaną podjęte na końcu łańcucha filtrów

  • Nieuwierzytelniony użytkownik próbujący uzyskać dostęp do zasobu publicznego - dozwolone
  • Nieuwierzytelniony użytkownik próbujący uzyskać dostęp do zabezpieczonego zasobu - 401-UnAuthorized
  • Uwierzytelniony użytkownik próbujący uzyskać dostęp do ograniczonego zasobu (ograniczony ze względu na jego rolę) - 403-Zabroniony

Uwaga: Żądanie użytkownika płynie nie tylko w wyżej wymienionych filtrów, ale istnieją inne filtry też nie pokazane tutaj (. ConcurrentSessionFilter, RequestCacheAwareFilter, SessionManagementFilter...)
To będzie inaczej, kiedy użyć filtru niestandardowego uwierzytelniania zamiast UsernamePasswordAuthenticationFilter.
Będzie inaczej, jeśli skonfigurujesz filtr uwierzytelniania JWT i .formLogin() i.e, UsernamePasswordAuthenticationFiltergo pominiesz , będzie to zupełnie inny przypadek.


Tylko w celach informacyjnych. Filtry w spring-web i spring-security
Uwaga: odwołaj się do nazwy pakietu na zdjęciu , ponieważ istnieje kilka innych filtrów z orm i mojego niestandardowego zaimplementowanego filtra.

wprowadź opis obrazu tutaj

Z Dokumentacji kolejność filtrów jest podana jako

  • ChannelProcessingFilter
  • ConcurrentSessionFilter
  • SecurityContextPersistenceFilter
  • LogoutFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • ConcurrentSessionFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

Możesz również wskazać
najpopularniejszy sposób uwierzytelniania nowoczesnej aplikacji internetowej?
różnica między uwierzytelnianiem a autoryzacją w kontekście Spring Security?

PraveenKumar Lalasangi
źródło
4

UsernamePasswordAuthenticationFilterjest używany tylko do /login, a ostatnie filtry nie są?

Nie, UsernamePasswordAuthenticationFilterrozszerza AbstractAuthenticationProcessingFilter, i zawiera a RequestMatcher, co oznacza, że ​​możesz zdefiniować własny adres URL przetwarzania, ten filtr obsługuje tylko RequestMatcherdopasowania adresu URL żądania, domyślny adres URL przetwarzania to /login.

Późniejsze filtry mogą nadal obsługiwać żądanie, jeśli jest UsernamePasswordAuthenticationFilterwykonywana chain.doFilter(request, response);.

Więcej informacji o podstawowych fitlerach

Czy element przestrzeni nazw logowania do formularza automatycznie konfiguruje te filtry?

UsernamePasswordAuthenticationFilterjest tworzony przez <form-login>, są to standardowe aliasy filtrów i kolejność

Czy każde żądanie (uwierzytelnione lub nie) dociera do FilterSecurityInterceptor w przypadku adresu URL bez logowania?

Zależy to od tego, czy fitlerzy sprzed lat odnoszą sukcesy, ale FilterSecurityInterceptorzwykle jest ostatnim fitlerem.

Czy skonfigurowanie dwóch elementów http powoduje utworzenie dwóch springSecurityFitlerChains?

Tak, każdy fitlerChain ma RequestMatcher, jeśli RequestMatcherpasuje do żądania, żądanie zostanie obsłużone przez fitlerów w łańcuchu fitler.

Wartość domyślna RequestMatcherpasuje do wszystkich żądań, jeśli nie skonfigurujesz wzorca lub możesz skonfigurować określony adres URL ( <http pattern="/rest/**").

Jeśli chcesz dowiedzieć się więcej o instalatorach, myślę, że możesz sprawdzić kod źródłowy w wiosennych zabezpieczeniach. doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)

chaoluo
źródło