Artikel ini memahami bagaimana filter dan pencegat bekerja melalui Contoh Sertifikasi Keamanan Sederhana Praktik Pengembangan.
Banyak artikel mengaitkan filter, pencegat, dan pendengar dengan Spring untuk dijelaskan, dan percaya bahwa filter, pencegat, dan pendengar banyak digunakan fungsi komponen yang disediakan oleh Spring.
Tapi secara tegas, filter dan pendengar milik API Servlet dan tidak ada hubungannya dengan Spring.
Karena filter mewarisi dari antarmuka javax.servlet.filter dan pendengar mewarisi dari antarmuka javax.servlet.servletcontextListener, hanya interceptor interceptor interface org.springframework.web.servlet.handlerinterceptor.
Flowchart di atas dirujuk dari informasi online, dan satu gambar bernilai ribuan kata. Setelah membaca artikel ini, Anda akan memiliki pemahaman yang lebih dalam tentang proses panggilan filter dan pencegat.
1. Ide Desain Sertifikasi Keselamatan
Terkadang, ketika jaringan internal dan eksternal memanggil API, persyaratan keamanan untuk persyaratan yang berbeda. Dalam banyak kasus, berbagai batasan pada jaringan eksternal panggilan API tidak diperlukan di intranet. Namun, ketika menggunakan gateway, API yang akan dipanggil oleh jaringan internal dan eksternal dapat digunakan bersama karena masalah biaya dan kompleksitas.
Untuk mewujudkan keamanan antarmuka istirahat, itu dapat dilakukan melalui kerangka kerja yang matang seperti SPRING STORITAS atau Shiro.
Namun, karena kerangka kerja keamanan seringkali rumit (saya menghitung keamanan musim semi, ada sekitar 11 modul inti, dan jumlah kode sumber Shiro juga cukup menakjubkan). Pada saat yang sama, konfigurasi yang kompleks dapat diperkenalkan (dapat membuat orang merasa lebih menyenangkan), yang tidak kondusif untuk pengembangan yang fleksibel dan cepat, penyebaran dan penyelidikan masalah tim kecil dan menengah.
Banyak tim membangun roda mereka sendiri untuk mencapai sertifikasi keselamatan. Contoh sertifikasi sederhana dalam artikel ini mengacu pada mantan tim pengembangan pabrik di mana saya berada, dan dapat dianggap sebagai layanan sertifikasi keamanan berbasis token.
Gagasan desain umum adalah sebagai berikut:
1. Kustomisasi header permintaan HTTP. Setiap kali API dipanggil, nilai token dilewatkan di header permintaan.
2. Tempatkan token di cache (seperti Redis), dan atur waktu kedaluwarsa dari berbagai kebijakan sesuai dengan bisnis dan API yang berbeda.
3. Token dapat mengatur daftar putih dan daftar hitam, yang dapat membatasi frekuensi panggilan API, memfasilitasi pengembangan dan pengujian, memfasilitasi penanganan darurat kelainan, dan bahkan untuk sementara menutup API.
4. Panggilan jaringan eksternal harus dikirimkan token. Token dapat dikaitkan dengan pengguna, seperti setiap kali Anda membuka halaman atau masuk untuk menghasilkan header permintaan menulis token, halaman tersebut memverifikasi validitas cookie dan token, dll.
Ada dua konsep dalam kerangka kerja keamanan musim semi, yaitu otentikasi dan otorisasi . Otentikasi mengacu pada pengguna yang dapat mengakses sistem, sementara otorisasi adalah sumber daya yang dapat diakses pengguna.
Untuk mencapai persyaratan otentikasi keamanan sederhana di atas, Anda mungkin perlu secara mandiri membuat layanan token untuk memastikan bahwa token itu unik secara global. Modul yang mungkin termasuk generator aliran khusus, CRM, enkripsi dan dekripsi, log, statistik API, cache, dll., Tetapi mereka sebenarnya terikat dengan lemah pada pengguna (CRM). Beberapa layanan publik yang terkait dengan pengguna, seperti SMS dan layanan email yang sering kami gunakan, juga dapat menyelesaikan panggilan keamanan melalui mekanisme token.
Singkatnya, sertifikasi keamanan sederhana dalam artikel ini sebenarnya sedikit berbeda dari otentikasi dan otorisasi yang disediakan oleh Kerangka Kerja Musim Semi. Tentu saja, metode perawatan "keselamatan" ini bukanlah hal baru bagi para profesional, tetapi dapat memblokir sejumlah besar pengguna pemula dari luar.
2. Kustomisasi filter
Mirip dengan Spring MVC, Spring Boot menyediakan banyak filter servlet (filter) untuk digunakan, dan secara otomatis menambahkan beberapa filter yang umum digunakan, seperti CharacterencodingFilter (digunakan untuk menangani masalah pengkodean), HiddenHttpMethodFilter (Formulir Formulir Hidden. Fungsi umum, seperti merekam log, menentukan apakah akan masuk, verifikasi izin, dll.
1. Header Permintaan Kustom
Ini sangat sederhana, tambahkan header permintaan kustom AuthToken di header permintaan:
@RequestMapping(value = "/getinfobyid", method = RequestMethod.POST) @ApiOperation("Query product information based on product Id") @ApiImplicitParams({ @ApiImplicitParam(paramType = "header", name = "authtoken", required = true, value = "authtoken", dataType = "String"), }) public Getgoodsbygoodsidresponse getgoodsbygoodsid (@Requestheader string authToken, @RequestBody getgoodsbygoodsidrequest permintaan) {return _goodsapiservice.getgoodsbygoodsid (permintaan); } getgoodsbygoodsidBidang AuthToken yang dimodifikasi oleh @Requestheader dapat ditampilkan di bawah kerangka seperti Swagger.
Setelah menelepon, Anda dapat melihat header permintaan sesuai dengan alat HTTP. Contoh dalam artikel ini adalah AuthToken (berbeda dari tanda kerangka kerja):
Catatan: Banyak alat httpClient mendukung header permintaan transmisi dinamis, seperti RestTemplate.
2. Menerapkan filter
Ada tiga metode dalam antarmuka filter, yaitu init, dofilter dan wadah. Ketika Anda melihat namanya, Anda mungkin akan mengetahui kegunaan utama mereka. Biasanya, kita hanya perlu memproses permintaan HTTP dalam metode dofilter:
Paket com.power.demo.controller.filter; import com.power.demo.common.appconst; import com.power.demo.common.bizresult; import com.power.demo.service.contract.Authtokenservice; impor com.power.demo.util.util.util.utger; com.power.demo.util.serializeutil; impor org.springframework.beans.factory.annotation.Autowired; impor org.springframework.stereotype.stpon; java.io.ioException; @ComponentPublic Class AuthTokenFilter mengimplementasikan filter {@Autowired private AuthTOKENSERVICE AUTHTOKENSERVICE; @Override public void init (filterconfig var1) melempar servletException {} @Override public void dofilter (permintaan servletRequest, respons servletResponse, rantai filterchain) melempar ioException, servletException {httpservletRequest req = (httpservlet {httpservletRequest; String token = req.getHeader (appconst.auth_token); BizResult <string> bizresult = authtokenservice.powercheck (token); System.out.println (Serializeutil.Serialize (BizResult)); if (bizresult.getisok () == true) {powerlogger.info ("Auth token filter lulus"); rantai.dofilter (permintaan, respons); } else {lempar servletException baru (bizresult.getMessage ()); }} @Override public void dashar () {}} authTokenFilterPerhatikan bahwa dari perspektif hierarki aktual, sebagian besar hal yang memproses lebih banyak lapisan ekspresi diproses. Tidak disarankan untuk secara langsung menggunakan lapisan akses data dalam filter. Meskipun saya telah melihat kode seperti itu berkali -kali dalam banyak proyek antik lama satu atau dua tahun yang lalu, dan ada preseden untuk menulis dengan cara ini dalam buku << Spring Practical >>.
3. Layanan Sertifikasi
Ini adalah logika bisnis utama. Kode sampel hanyalah cara sederhana untuk menuliskan ide, dan tidak boleh digunakan dengan mudah di lingkungan produksi:
Paket com.power.demo.service.impl; import com.power.demo.cache.powercachebuilder; import com.power.demo.common.bizresult; import com.power.demo.service.contract.authtokenservice; impor org.power.demo. org.springframework.stereotype.component; impor org.springframework.util.stringutils; @ComponentPublic kelas AuthTOKENSERVICEIMPL mengimplementasikan AuthTOKENSERVICE {@Autowired Private PowerCacheBuilder CacheBuilder; / * * Verifikasi apakah token header permintaan legal * */ @override BizResult Public <string> powercheck (Token String) {BizResult <String> bizresult = BizResult baru <> (true, "Verifikasi lulus"); System.out.println ("Nilai token adalah:" + token); if (stringutils.isempty (token) == true) {bizresult.setfail ("authToken is OMPOMED"); Return BizResult; } // memproses blacklist bizresult = checkForbidlist (token); if (bizresult.getisok () == false) {return bizresult; } // memproses whitelist BizResult = chossallowlist (token); if (bizresult.getisok () == false) {return bizresult; } String key = string.format ("power.AuthTokenService.%S", token); //cachebuilder.set(key, token); //cachebuilder.set(key, token.touppercase ()); // Fetch String Existtoken dari cache = cacheBuilder.get (key); if (stringutils.isempty (extrictoken) == true) {bizresult.setFail (string.format ("ini authToken:%s", token)); Return BizResult; } // Bandingkan apakah tokennya sama boolean isequal = token.equals (extristoken); if (isequal == false) {bizresult.setFail (string.format ("AuthToken ilegal:%s", token)); Return BizResult; } // Lakukan sesuatu Return BizResult; }} AuthtokenserviceImplAnda dapat merujuk ke layanan cache yang Anda gunakan di sini, yang juga merupakan ringkasan dari pengalaman saya di pabrik sebelumnya.
4. Daftar filter
Ada dua cara umum untuk menulis:
(1) Gunakan anotasi @WebFilter untuk mengidentifikasi filter
@Order (1) @WebFilter (urlpatterns = {"/API/V1/Goods/*", "/API/V1/UserInfo/*"}) Kelas Publik AuthTokenFilter mengimplementasikan filter {Menggunakan anotasi @WebFilter, Anda juga dapat menggunakan anotasi @order bersamaan dengan anotasi @order. Anotasi @order mewakili urutan penyaringan. Semakin kecil nilainya, semakin banyak Anda menjalankannya terlebih dahulu. Ukuran pesanan ini sama bermanfaatnya dengan memproses siklus hidup permintaan HTTP selama proses pemrograman kami. Tentu saja, jika pesanan tidak ditentukan, urutan filter disebut berlawanan dengan urutan filter yang ditambahkan, dan implementasi filter adalah pola rantai tanggung jawab.
Akhirnya, tambahkan anotasi @ServerComponentScan ke kelas startup untuk menggunakan filter khusus secara normal.
(2) Gunakan filterregistrationBean untuk menyesuaikan pendaftaran filter
Artikel ini menggunakan implementasi kedua untuk mengimplementasikan pendaftaran filter khusus:
Paket com.power.demo.controller.filter; impor com.google.common.collect.lists; impor org.springframework.beans.factory.annotation.Autowired; impor org.spramework.boot.web.servlet.filterregationBean. org.springframework.context.annotation.configuration; impor org.springframework.stereotype.component; import java.util.list;@configuration@componentpublic class restfilterconfig {@autowired private AuthTokenFilter filter; @Bean filterregistrationBean filterregistrationBean () {filterregistrationBean RegistrationBean = new filterregistrationBean (); RegistrationBean.setFilter (filter); // Set (fuzzy) Pencocokan Daftar URL <String> urlpatterns = lists.newarraylist (); urlpatterns.add ("/API/V1/Good/*"); urlpatterns.add ("/API/V1/userInfo/*"); RegistrationBean.setUrlPatterns (urlpatterns); RegistrationBean.Setorder (1); RegistrationBean.setenabled (true); Return RegistrationBean; }} RestfilterconfigHarap beri perhatian khusus pada urlpatterns. Atribut URLPatterns menentukan pola URL yang akan difilter. Parameter ini sangat penting untuk area tindakan filter.
Daftarkan filter, dan ketika Spring Boot dimulai, itu akan secara otomatis menambahkan filter rantai panggilan aplikasifilterchain saat mendeteksi kacang dengan javax.servlet.filter.
Hubungi API untuk mencoba efeknya:
Biasanya, kami menyesuaikan peningkatan Global Unified Expection Management GlobalExceptionHandler di bawah Spring Boot (akan sedikit berbeda dari yang di atas).
Menurut praktik saya, pengecualian yang dilemparkan ke dalam filter tidak akan ditangkap dan diproses oleh peningkatan manajemen pengecualian yang unik secara global. Ini berbeda dari Interceptor Inteceptor dan Custom AOP Interceptor yang diperkenalkan pada artikel berikutnya.
Pada titik ini, layanan otentikasi keamanan sederhana yang diimplementasikan melalui filter khusus dilakukan.
3. Interceptor khusus
1. Menerapkan pencegat
Mewarisi antarmuka handlerinterceptor dan mengimplementasikan interseptor. Metode antarmuka adalah sebagai berikut:
Prehandle dieksekusi sebelum permintaan eksekusi
Posthandle adalah akhir dari eksekusi permintaan
Setelah pelaksanaan setelah rendering tampilan selesai
Paket com.power.demo.controller.interceptor; import com.power.demo.common.appconst; import com.power.demo.common.bizresult; import com.power.demo.service.contract.Authtokenservice; impor com.power.demo.util.util.util.util.utger; com.power.demo.util.serializeutil; impor org.springframework.beans.factory.annotation.Autowired; impor org.springframework.stereotype.stereTypon; impor org.springpramework.web.servlet.handlererintercepor; impor org.springfring.web javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse;/ * * Token Authentication Interceptor */ @ComponentPublic AuthTokenCervice; / * * Jalankan sebelum permintaan eksekusi * */ @Override Public Boolean Prehandle (permintaan httpservletRequest, respons httpservletResponse, penangan objek) melempar pengecualian {boolean handleresult = false; String token = request.getHeader (appconst.auth_token); BizResult <string> bizresult = authtokenservice.powercheck (token); System.out.println (Serializeutil.Serialize (BizResult)); handleresult = bizresult.getisok (); Powerlogger.info ("AUTH Token Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor Interceptor lulus"); } else {lempar pengecualian baru (bizresult.getMessage ()); } return handleresult; } / * * Permintaan mengakhiri eksekusi * * / @Override public void posthandle (permintaan httpservletRequest, httpservletResponse respons, handler objek, model modelAndView) Lempar Exception {} / * execute setelah rending view diselesaikan * * / @override void aftercomplide void aftercomplide voidpspspsseS Respons, Object Handler, Exception Ex) melempar Exception {}} authTokenInterceptorDalam contoh, kami memilih untuk melakukan otentikasi keamanan token sebelum permintaan dieksekusi.
Layanan otentikasi adalah AuthtokenService yang diperkenalkan di filter, dan lapisan logika bisnis digunakan kembali.
2. Daftarkan pencegat
Tentukan kelas InterceptorConfig, yang diwarisi dari WebMVCConfigurationsupport, dan WebMvCconfigurerAdapter sudah ketinggalan zaman.
Suntikkan AuthTokenInceptor sebagai kacang, URL dan filter yang dicegat dengan penyadapan pencegat Pengaturan lainnya sangat mirip:
Paket com.power.demo.controller.Interceptor; import com.google.common.collect.lists; impor org.springframework.context.annotation.bean; impor org.spramework.context.annotation.onfigurasi; impor org.springframework.sere.sterexon.snotation org.springframework.web.servlet.config.annotation.defaultSerVlethandlerConfigurer; impor org.springframework.web.servlet.config.annotation.inteporregistry; impor org.springframework.web.servlet.config.annotation org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import java.util.List;@Configuration@Componentpublic class InterceptorConfig extends WebMvcConfigurationSupport { //WebMvcConfigurerAdapter is outdated private static final String FAVICON_URL = "/favicon.ico"; /*** Ditemukan bahwa jika WebMvCconfigurationsupport diwarisi, konten yang relevan yang dikonfigurasi dalam YML akan tidak valid. * *@param Registry */@Override public void addResourceHandlers (ResourceHandlerRegistry Registry) {Registry.AdResourceHandler ("/"). AddResourcelocations ("/**"); Registry.addResourceHandler ("/static/**"). AddResourcelocations ("classpath:/static/"); } / *** Mengkonfigurasi pemrosesan servlet* / @Override void public configuredefaultserVlethandling (DefaultSerVlethandLerConfigurer Configure) {configurer.enable (); } @Override public void addInterceptors (intercepTorRegistry registry) {// set (fuzzy) pencocokan daftar URL <string> urlpatterns = lists.newarraylist (); urlpatterns.add ("/API/V1/Good/*"); urlpatterns.add ("/API/V1/userInfo/*"); registry.addInterceptor (authTokenInterceptor ()). AddPathPatterns (urlpatterns) .excludePathPatterns (favicon_url); Super.AddInterceptors (Registry); } // Tulis pencegat sebagai kacang ke dalam konfigurasi @bean public authTokenIncepor authTokenInterceptor () {return new AuthTokenInterceptor (); }} InterceptorConfigSetelah memulai aplikasi, Anda dapat melihat efek intersepsi interseptor dengan memanggil antarmuka. Global Unified Excion Management GlobalExceptionHandler menangani pengecualian berikut setelah menangkapnya:
Hampir sama dengan pesan kesalahan utama yang ditampilkan oleh filter, tetapi informasi tumpukan lebih kaya.
4. Perbedaan antara filter dan interseptor
Perbedaan utama adalah sebagai berikut:
1. Pencegat terutama didasarkan pada mekanisme refleksi Java, sedangkan filter didasarkan pada callback fungsi
2. Interceptor tidak bergantung pada wadah servlet, filter mengandalkan wadah servlet
3. Pencegat hanya dapat mengerjakan permintaan tindakan, sementara filter dapat bekerja pada hampir semua permintaan.
4. Interceptor dapat mengakses objek dalam konteks tindakan dan tumpukan nilai, tetapi filter tidak dapat mengaksesnya.
5. Selama siklus hidup suatu tindakan, pencegat dapat dipanggil beberapa kali, sedangkan filter hanya dapat dipanggil sekali ketika wadah diinisialisasi.
Beberapa artikel yang saya rujuk mengatakan bahwa "pencegat dapat memperoleh berbagai kacang dalam wadah IOC, tetapi filter tidak bisa. Ini sangat penting. Menyuntikkan layanan ke Interceptor dapat memanggil logika bisnis." Setelah verifikasi yang sebenarnya, ini salah.
CATATAN: Waktu pemicu filter adalah setelah wadah dan sebelum servlet, sehingga parameter entri dari dofilter filter (permintaan servletRequest, respons respons servlet, rantai filterchain) adalah servletRequest, bukan httpservletRequest, karena filter sebelum httpservlet. Angka berikut dapat memberi Anda pemahaman yang lebih intuitif tentang waktu eksekusi filter dan interseptor:
Hanya permintaan yang disahkan oleh DispatcherServlet yang akan diikuti oleh rantai pencegat. Permintaan servlet khusus tidak akan dicegat. Misalnya, alamat servlet khusus kami http: // localhost: 9090/testservlet tidak akan dicegat oleh pencegat. Tetapi tidak peduli servlet mana yang menjadi miliknya, filter akan dieksekusi selama itu sesuai dengan aturan filter filter.
Menurut analisis di atas, pemahaman prinsipnya akan sederhana, bahkan filter ASP.NET akan sama.
Masalah: Mencapai otentikasi keamanan yang lebih fleksibel
Di bawah Java Web, melalui filter filter khusus atau Interceptor Interceptor, otentikasi aman dari API pencocokan spesifik dapat dicapai, seperti mencocokkan semua API, mencocokkan satu atau beberapa API, dll., Tetapi kadang -kadang pola pencocokan ini relatif tidak ramah kepada pengembang.
Kita dapat merujuk pada keamanan musim semi untuk mencapai fungsi yang kuat melalui anotasi + spel.
Misalnya, di ASP.NET, kami sering menggunakan fitur resmi, yang dapat ditambahkan ke kelas atau diterapkan pada metode, dan dapat mengontrol otentikasi keamanan secara lebih dinamis dan fleksibel.
Kami tidak memilih Spring Security, sehingga kami dapat menerapkan sertifikasi keamanan fleksibel yang mirip dengan yang diotorisasi. Teknologi implementasi utama adalah AOP yang kami kenal.
Pengetahuan dasar untuk mencapai intersepsi yang lebih fleksibel melalui metode AOP tidak akan disebutkan dalam artikel ini. Lebih banyak topik tentang AOP akan dibagikan di artikel berikutnya.
Meringkaskan
Di atas adalah apa yang diperkenalkan editor kepada Anda. Spring Boot menggunakan filter dan pencegat untuk mencapai otentikasi antarmuka REST yang sederhana dan aman. Saya harap ini akan membantu semua orang. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas semua orang tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!