Saya menyadari bahwa keamanan Spring membangun di atas rantai filter, yang akan mencegat permintaan, mendeteksi (tidak adanya) otentikasi, mengalihkan ke titik masuk otentikasi atau meneruskan permintaan ke layanan otorisasi, dan akhirnya membiarkan permintaan tersebut mengenai servlet atau membuang pengecualian keamanan (tidak diauthentikasi atau tidak diotorisasi). DelegatingFitlerProxy merekatkan filter ini bersama-sama. Untuk melakukan tugas mereka, layanan akses filter ini seperti UserDetailsService dan AuthenticationManager .
Filter utama dalam rantai adalah (sesuai urutan)
- SecurityContextPersistenceFilter (mengembalikan Otentikasi dari JSESSIONID)
- UsernamePasswordAuthenticationFilter (melakukan otentikasi)
- ExceptionTranslationFilter (menangkap pengecualian keamanan dari FilterSecurityInterceptor)
- FilterSecurityInterceptor (dapat membuang pengecualian otentikasi dan otorisasi)
Saya bingung bagaimana filter ini digunakan. Apakah itu untuk form yang disediakan form-login, UsernamePasswordAuthenticationFilter hanya digunakan untuk / login , dan filter yang terakhir tidak? Apakah elemen namespace form-login otomatis mengkonfigurasi filter ini? Apakah setiap permintaan (dikonfirmasi atau tidak) mencapai FilterSecurityInterceptor untuk url non-login?
Bagaimana jika saya ingin mengamankan API REST saya dengan token JWT , yang diambil dari login? Saya harus mengkonfigurasi dua http
tag konfigurasi namespace , hak? Satu untuk / masuk dengan UsernamePasswordAuthenticationFilter
, dan satu lagi untuk url REST, dengan kustom JwtAuthenticationFilter
.
Apakah mengonfigurasi dua http
elemen membuat dua springSecurityFitlerChains
? Apakah UsernamePasswordAuthenticationFilter
dimatikan secara default, sampai saya menyatakan form-login
? Bagaimana cara saya mengganti SecurityContextPersistenceFilter
dengan filter yang akan diperoleh Authentication
dari yang sudah ada JWT-token
bukan JSESSIONID
?
sumber
Jawaban:
Rantai filter keamanan Pegas adalah mesin yang sangat kompleks dan fleksibel.
Melihat dokumentasi stabil 4.2.1 dokumentasi saat ini , bagian 13.3 Memesan Filter Anda dapat melihat organisasi filter seluruh rantai filter:
Sekarang, saya akan mencoba melanjutkan pertanyaan Anda satu per satu:
Setelah Anda mengonfigurasi
<security-http>
bagian, untuk masing-masing Anda setidaknya harus menyediakan satu mekanisme otentikasi. Ini harus menjadi salah satu filter yang cocok dengan grup 4 di bagian 13.3 Memesan Filter dari dokumentasi Spring Security yang baru saja saya referensikan.Ini adalah keamanan minimum yang valid: Elemen http yang dapat dikonfigurasi:
Lakukan saja, filter ini dikonfigurasikan dalam proksi rantai filter:
Catatan: Saya mendapatkannya dengan membuat RestController sederhana yang @Mengedit FilterChainProxy dan mengembalikan isinya:
Di sini kita dapat melihat bahwa hanya dengan mendeklarasikan
<security:http>
elemen dengan satu konfigurasi minimum, semua filter default disertakan, tetapi tidak ada yang merupakan tipe Otentikasi (grup ke-4 di bagian 13.3 Memesan Filter). Jadi itu sebenarnya berarti bahwa hanya dengan mendeklarasikansecurity:http
elemen, SecurityContextPersistenceFilter, ExceptionTranslationFilter dan FilterSecurityInterceptor dikonfigurasi secara otomatis.Bahkan, satu mekanisme pemrosesan otentikasi harus dikonfigurasi, dan bahkan kacang namespace keamanan memproses klaim untuk itu, melemparkan kesalahan selama startup, tetapi itu dapat dilewati dengan menambahkan atribut entry-point-ref di
<http:security>
Jika saya menambahkan dasar
<form-login>
ke konfigurasi, dengan cara ini:Sekarang, filterChain akan seperti ini:
Sekarang, dua filter ini adalah org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter dan org.springframework.security.web.authentication.ui.KelemahanLoginPageGeneratingFilter dibuat dan dikonfigurasi dalam FilterChainProxy.
Jadi, sekarang, pertanyaannya:
Ya, ini digunakan untuk mencoba menyelesaikan mekanisme pemrosesan login seandainya permintaan cocok dengan url UsernamePasswordAuthenticationFilter. URL ini dapat dikonfigurasi atau bahkan diubah perilakunya agar sesuai dengan setiap permintaan.
Anda juga dapat memiliki lebih dari satu mekanisme pemrosesan Otentikasi yang dikonfigurasi dalam FilterchainProxy yang sama (seperti HttpBasic, CAS, dll).
Tidak, elemen form-login mengonfigurasiFilter UsernamePasswordAUthentication, dan jika Anda tidak memberikan url halaman login, itu juga mengkonfigurasi org.springframework.security.web.authentication.ui.FefaultLoginPageGeneratingFilter, yang berakhir dengan login masuk otomatis yang dibuat secara otomatis. halaman.
Filter lain secara otomatis dikonfigurasi secara default hanya dengan membuat
<security:http>
elemen tanpasecurity:"none"
atribut.Setiap permintaan harus mencapainya, karena merupakan elemen yang menangani apakah permintaan tersebut memiliki hak untuk mencapai url yang diminta. Tetapi beberapa filter yang diproses sebelumnya mungkin menghentikan pemrosesan rantai filter tanpa menelepon
FilterChain.doFilter(request, response);
. Misalnya, filter CSRF mungkin menghentikan pemrosesan rantai filter jika permintaan tidak memiliki parameter csrf.Tidak, Anda tidak dipaksa melakukan ini. Anda bisa mendeklarasikan keduanya
UsernamePasswordAuthenticationFilter
danJwtAuthenticationFilter
dalam elemen http yang sama, tetapi itu tergantung pada perilaku konkret dari setiap filter ini. Kedua pendekatan itu mungkin, dan mana yang dipilih secara final tergantung pada preferensi mereka sendiri.Ya itu benar
Ya, Anda bisa melihatnya di filter yang muncul di setiap konfigurasi yang saya posting
Anda dapat menghindari SecurityContextPersistenceFilter, cukup mengkonfigurasi strategi sesi di
<http:element>
. Cukup konfigurasikan seperti ini:<security:http create-session="stateless" >
Atau, Dalam hal ini Anda bisa menimpanya dengan filter lain, dengan cara ini di dalam
<security:http>
elemen:EDIT:
Ini akhirnya tergantung pada implementasi setiap filter itu sendiri, tetapi memang benar fakta bahwa filter otentikasi terakhir setidaknya mampu menimpa otentikasi sebelumnya yang akhirnya dibuat oleh filter sebelumnya.
Tapi ini tidak akan terjadi. Saya memiliki beberapa kasus produksi di layanan REST aman di mana saya menggunakan semacam token otorisasi yang dapat diberikan baik sebagai header Http atau di dalam badan permintaan. Jadi saya mengkonfigurasi dua filter yang memulihkan token itu, dalam satu kasus dari Http Header dan yang lainnya dari badan permintaan dari permintaan sisanya sendiri. Memang benar fakta bahwa jika satu permintaan http memberikan token otentikasi baik sebagai tajuk Http maupun di dalam badan permintaan, kedua filter akan mencoba menjalankan mekanisme otentikasi yang mendelegasikannya kepada manajer, tetapi bisa dengan mudah dihindari hanya dengan memeriksa apakah permintaan tersebut sudah diautentikasi hanya pada awal
doFilter()
metode setiap filter.Memiliki lebih dari satu filter otentikasi terkait dengan memiliki lebih dari satu penyedia otentikasi, tetapi jangan memaksanya. Dalam kasus yang saya paparkan sebelumnya, saya memiliki dua filter otentikasi tetapi saya hanya memiliki satu penyedia otentikasi, karena kedua filter membuat jenis objek otentikasi yang sama sehingga dalam kedua kasus manajer otentikasi mendelegasikannya ke penyedia yang sama.
Dan berlawanan dengan ini, saya juga memiliki skenario di mana saya menerbitkan hanya satu UsernamePasswordAuthenticationFilter tetapi kredensial pengguna keduanya dapat dimuat dalam DB atau LDAP, jadi saya memiliki dua penyedia dukungan UsernamePasswordAuthenticationToken, dan delegasi AuthenticationManager segala upaya otentikasi dari filter ke penyedia. secuensial untuk memvalidasi kredensial.
Jadi, saya pikir sudah jelas bahwa baik jumlah filter otentikasi menentukan jumlah penyedia otentikasi maupun jumlah penyedia menentukan jumlah filter.
Saya tidak melihat dengan saksama filter ini sebelumnya, tetapi setelah pertanyaan terakhir Anda, saya telah memeriksa implementasinya, dan seperti biasanya di Spring, hampir semuanya dapat dikonfigurasikan, diperluas atau ditimpa.
The SecurityContextPersistenceFilter delegasi dalam SecurityContextRepository pelaksanaan pencarian untuk SecurityContext. Secara default, sebuah HttpSessionSecurityContextRepository digunakan, tetapi ini dapat diubah menggunakan salah satu konstruktor filter. Jadi mungkin lebih baik untuk menulis SecurityContextRepository yang sesuai dengan kebutuhan Anda dan hanya mengkonfigurasinya di SecurityContextPersistenceFilter, percaya pada perilaku terbukti itu daripada mulai membuat semuanya dari awal.
sumber
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)}
Tidak,
UsernamePasswordAuthenticationFilter
memanjangAbstractAuthenticationProcessingFilter
, dan ini berisiRequestMatcher
, yang berarti Anda dapat menentukan url pemrosesan Anda sendiri, filter ini hanya menangani yangRequestMatcher
cocok dengan url permintaan, url pemrosesan default adalah/login
.Filter selanjutnya masih dapat menangani permintaan, jika
UsernamePasswordAuthenticationFilter
dijalankanchain.doFilter(request, response);
.Lebih detail tentang core fitlers
UsernamePasswordAuthenticationFilter
dibuat oleh<form-login>
, ini adalah Standar Filter Alias dan PemesananItu tergantung pada apakah sebelum fitlers berhasil, tetapi
FilterSecurityInterceptor
apakah fitler terakhir biasanya.Ya, setiap rantai fitler memiliki
RequestMatcher
, jikaRequestMatcher
cocok dengan permintaan, permintaan tersebut akan ditangani oleh orang yang cocok dalam rantai fitler.Defaultnya
RequestMatcher
cocok dengan semua permintaan jika Anda tidak mengonfigurasi pola, atau Anda dapat mengonfigurasi url spesifik (<http pattern="/rest/**"
).Jika Anda ingin tahu lebih banyak tentang fitlers, saya pikir Anda dapat memeriksa kode sumber di keamanan musim semi.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
sumber
Keamanan pegas adalah kerangka kerja berbasis filter, itu menanam WALL (HttpFireWall) sebelum aplikasi Anda dalam hal filter proxy atau kacang dikelola musim semi. Permintaan Anda harus melewati beberapa filter untuk mencapai API Anda.
Urutan eksekusi di Spring Security
WebAsyncManagerIntegrationFilter
Menyediakan integrasi antara SecurityContext dan Spring Web's WebAsyncManager.SecurityContextPersistenceFilter
Filter ini hanya akan mengeksekusi sekali per permintaan, Mengisi SecurityContextHolder dengan informasi yang diperoleh dari SecurityContextRepository yang dikonfigurasi sebelum permintaan dan menyimpannya kembali dalam repositori setelah permintaan selesai dan membersihkan pemegang konteks.Permintaan diperiksa untuk sesi yang ada. Jika permintaan baru, SecurityContext akan dibuat lain jika permintaan memiliki sesi maka konteks keamanan yang ada akan diperoleh dari respositori .
HeaderWriterFilter
Saring implementasi untuk menambahkan header ke respons saat ini.LogoutFilter
Jika url permintaan adalah/logout
(untuk konfigurasi default) atau jika url permintaan, urlRequestMatcher
dikonfigurasi diLogoutConfigurer
kemudianLogoutConfigurer
/
atau url keberhasilan logout dikonfigurasi atau memanggil logoutSuccessHandler dikonfigurasi.UsernamePasswordAuthenticationFilter
HTTP POST
) default/login
atau cocok dengan yang.loginProcessingUrl()
dikonfigurasikan diFormLoginConfigurer
kemudianUsernamePasswordAuthenticationFilter
mencoba otentikasi.usernameParameter(String)
,passwordParameter(String)
..loginPage()
menimpa defaultAuthentication
objek (UsernamePasswordAuthenticationToken
atau implementasi apa punAuthentication
dalam kasus filter autentikasi khusus Anda) dibuat.authenticationManager.authenticate(authToken)
akan dipanggilAuthenticationProvider
metode otentikasi mencoba semua penyedia auth dan memeriksa salah satu darisupports
authToken / objek autentikasi penyedia, penyedia auth yang mendukung akan digunakan untuk otentikasi. dan mengembalikan objek Otentikasi jika otentikasi berhasil dilakukanAuthenticationException
.authenticationSuccessHandler
akan dipanggil yang mengalihkan ke url target yang dikonfigurasi (standarnya adalah/
)SecurityContextHolderAwareRequestFilter
, jika Anda menggunakannya untuk menginstal Spring Security, sadar HttpServletRequestWrapper ke dalam wadah servlet AndaAnonymousAuthenticationFilter
Mendeteksi jika tidak ada objek otentikasi di SecurityContextHolder, jika tidak ada objek otentikasi yang ditemukan, membuatAuthentication
objek (AnonymousAuthenticationToken
) dengan otoritas yang diberikanROLE_ANONYMOUS
. Di siniAnonymousAuthenticationToken
memfasilitasi pengidentifikasian permintaan berikutnya yang tidak diautentikasi oleh pengguna.ExceptionTranslationFilter
, untuk mendapatkan pengecualian Spring Security sehingga respons kesalahan HTTP dapat dikembalikan atau AuthenticationEntryPoint yang sesuai dapat diluncurkanFilterSecurityInterceptor
Akan ada
FilterSecurityInterceptor
yang datang hampir terakhir dalam rantai filter yang mendapat objek Otentikasi dariSecurityContext
dan mendapat daftar otoritas yang diberikan (peran diberikan) dan itu akan membuat keputusan apakah akan mengizinkan permintaan ini untuk mencapai sumber daya yang diminta atau tidak, keputusan dibuat dengan mencocokkan dengan diizinkanAntMatchers
dikonfigurasi dalamHttpSecurityConfiguration
.Pertimbangkan pengecualian 401-UnAuthorized dan 403-Forbidden. Keputusan ini akan dilakukan pada akhirnya dalam rantai filter
Catatan: User Permintaan mengalir tidak hanya di atas filter disebutkan, tetapi ada orang lain filter terlalu tidak ditampilkan di sini (.
ConcurrentSessionFilter
,RequestCacheAwareFilter
,SessionManagementFilter
...)Ini akan berbeda bila Anda menggunakan filter auth kustom Anda bukan
UsernamePasswordAuthenticationFilter
.Ini akan berbeda jika Anda mengonfigurasi JWT auth filter dan menghilangkannya
.formLogin() i.e, UsernamePasswordAuthenticationFilter
akan menjadi kasus yang sama sekali berbeda.Hanya sebagai referensi. Filter di spring-web dan spring-security
Catatan: lihat nama paket di pic , karena ada beberapa filter lain dari orm dan filter kustom yang diimplementasikan.
Anda juga dapat merujuk
cara paling umum untuk mengautentikasi aplikasi web modern?
perbedaan antara otentikasi dan otorisasi dalam konteks Spring Security?
sumber