Memperbaiki 401 dengan CORS Preflights dan Spring Security

1. Ikhtisar

Dalam tutorial singkat ini, kita akan belajar bagaimana mengatasi kesalahan "Respon untuk preflight memiliki kode status HTTP 401 tidak valid", yang dapat terjadi pada aplikasi yang mendukung komunikasi lintas sumber dan menggunakan Keamanan Musim Semi.

Pertama, kita akan melihat apa itu permintaan lintas sumber dan kemudian kita akan memperbaiki contoh yang bermasalah.

2. Permintaan Lintas Asal

Singkatnya, permintaan lintas-sumber adalah permintaan HTTP yang asal dan target permintaannya berbeda. Ini adalah kasusnya, misalnya, ketika aplikasi web disajikan dari satu domain dan browser mengirimkan permintaan AJAX ke server di domain lain.

Untuk mengelola permintaan lintas sumber, server perlu mengaktifkan mekanisme tertentu yang disebut CORS, atau Berbagi Sumber Daya Lintas Asal.

Langkah pertama di CORS adalah permintaan OPTIONS untuk menentukan apakah target permintaan mendukungnya. Ini disebut permintaan pra-penerbangan.

Server kemudian dapat menanggapi permintaan pra-penerbangan dengan kumpulan tajuk:

  • Access-Control-Allow-Origin : Menentukan asal yang mungkin memiliki akses ke sumber daya. A '*' mewakili asal mana pun
  • Access-Control-Allow-Methods : Menunjukkan metode HTTP yang diizinkan untuk permintaan lintas sumber
  • Access-Control-Allow-Headers : Menunjukkan header permintaan yang diizinkan untuk permintaan lintas sumber
  • Access-Control-Max-Age : Menentukan waktu kedaluwarsa hasil permintaan preflight yang disimpan dalam cache

Jadi, jika permintaan pra-penerbangan tidak memenuhi ketentuan yang ditentukan dari header respons ini, permintaan tindak lanjut yang sebenarnya akan memunculkan error terkait permintaan lintas sumber.

Sangat mudah untuk menambahkan dukungan CORS ke layanan bertenaga Spring kami, tetapi jika dikonfigurasi dengan tidak benar, permintaan pra-penerbangan ini akan selalu gagal dengan 401.

3. Membuat REST API yang mendukung CORS

Untuk mensimulasikan masalah, pertama-tama mari buat REST API sederhana yang mendukung permintaan lintas sumber:

@RestController @CrossOrigin("//localhost:4200") public class ResourceController { @GetMapping("/user") public String user(Principal principal) { return principal.getName(); } }

The @CrossOrigin penjelasan memastikan bahwa API kami hanya dapat diakses dari asal disebutkan dalam argumen.

4. Mengamankan REST API Kami

Sekarang mari amankan REST API kami dengan Spring Security:

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); } }

Di kelas konfigurasi ini, kami telah menerapkan otorisasi untuk semua permintaan yang masuk. Akibatnya, ini akan menolak semua permintaan tanpa token otorisasi yang valid.

5. Membuat Permintaan Pra-penerbangan

Sekarang setelah kami membuat REST API kami, mari coba permintaan pra-penerbangan menggunakan curl :

curl -v -H "Access-Control-Request-Method: GET" -H "Origin: //localhost:4200" -X OPTIONS //localhost:8080/user ... < HTTP/1.1 401 ... < WWW-Authenticate: Basic realm="Realm" ... < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers < Access-Control-Allow-Origin: //localhost:4200 < Access-Control-Allow-Methods: POST < Access-Control-Allow-Credentials: true < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH ...

Dari keluaran perintah ini, kita dapat melihat bahwa permintaan tersebut ditolak dengan 401.

Karena ini adalah perintah curl , kita tidak akan melihat kesalahan "Respon untuk preflight memiliki kode status HTTP 401 yang tidak valid" pada keluarannya.

Tapi kita bisa mereproduksi kesalahan ini dengan membuat aplikasi front end yang menggunakan REST API kita dari domain berbeda dan menjalankannya di browser.

6. Solusi

Kami belum secara eksplisit mengecualikan permintaan preflight dari otorisasi dalam konfigurasi Keamanan Musim Semi kami . Ingatlah bahwa Keamanan Musim Semi mengamankan semua titik akhir secara default.

Akibatnya, API kami mengharapkan token otorisasi dalam permintaan OPTIONS juga.

Spring memberikan solusi out of the box untuk mengecualikan permintaan OPTIONS dari pemeriksaan otorisasi:

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // ... http.cors(); } }

Metode cors () akan menambahkan CorsFilter yang disediakan Spring ke konteks aplikasi yang pada gilirannya mengabaikan pemeriksaan otorisasi untuk permintaan OPTIONS.

Sekarang kita dapat menguji aplikasi kita lagi dan melihat apakah itu berfungsi.

7. Kesimpulan

Dalam artikel singkat ini, kami telah mempelajari cara memperbaiki kesalahan "Respons untuk preflight memiliki kode status HTTP 401 yang tidak valid" yang ditautkan dengan Keamanan Musim Semi dan permintaan lintas sumber.

Perhatikan bahwa, dengan contoh, klien dan API harus berjalan di domain atau port yang berbeda untuk membuat ulang masalah. Misalnya, kita dapat memetakan nama host default ke klien dan alamat IP mesin ke REST API kita saat berjalan di mesin lokal.

Seperti biasa, contoh yang ditunjukkan dalam tutorial ini dapat ditemukan di Github.