Memperbaiki 401s dengan CORS Preflights dan Spring Security

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kita akan belajar bagaimana menyelesaikan ralat "Respons untuk preflight mempunyai kod status HTTP 401 yang tidak valid", yang dapat terjadi pada aplikasi yang mendukung komunikasi lintas asal dan menggunakan Spring Security.

Mula-mula, kita akan melihat apakah permintaan asal silang dan kemudian kita akan memperbaiki contoh yang bermasalah.

2. Permintaan Merentas Asal

Permintaan silang asal, ringkasnya, permintaan HTTP di mana asal dan sasaran permintaannya berbeza. Ini terjadi, misalnya, ketika aplikasi web dilayani dari satu domain dan penyemak imbas mengirimkan permintaan AJAX ke pelayan di domain lain.

Untuk mengurus permintaan silang asal, pelayan perlu mengaktifkan mekanisme tertentu yang dikenali sebagai CORS, atau Perkongsian Sumber Silang Asal.

Langkah pertama dalam CORS adalah permintaan PILIHAN untuk menentukan sama ada sasaran permintaan menyokongnya. Ini dipanggil permintaan sebelum penerbangan.

Pelayan kemudian dapat menanggapi permintaan sebelum penerbangan dengan koleksi tajuk:

  • Access-Control-Allow-Origin : Menentukan asal mana yang mungkin mempunyai akses ke sumber. A '*' mewakili sebarang asal
  • Access-Control-Allow-Methods : Menunjukkan kaedah HTTP yang dibenarkan untuk permintaan silang asal
  • Akses-Kawalan-Benarkan-Tajuk : Menunjukkan tajuk permintaan yang dibenarkan untuk permintaan silang asal
  • Access-Control-Max-Age : Menentukan masa tamat hasil permintaan preflight cache

Jadi, jika permintaan sebelum penerbangan tidak memenuhi syarat yang ditentukan dari tajuk respons ini, permintaan susulan yang sebenarnya akan menimbulkan kesalahan yang berkaitan dengan permintaan silang asal.

Sangat mudah untuk menambahkan sokongan CORS ke perkhidmatan berkuasa Spring kami, tetapi jika dikonfigurasi dengan tidak betul, permintaan sebelum penerbangan ini akan selalu gagal dengan 401.

3. Membuat REST API yang didayakan CORS

Untuk mensimulasikan masalah, mari kita buat REST API ringkas yang menyokong permintaan silang:

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

The @CrossOrigin anotasi memastikan bahawa API kami boleh diakses hanya daripada sumber yang disebut dalam hujahnya.

4. Melindungi API REST Kami

Sekarang selamatkan 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 kebenaran untuk semua permintaan masuk. Akibatnya, ia akan menolak semua permintaan tanpa token kebenaran yang sah.

5. Membuat Permintaan Pra-penerbangan

Setelah membuat API REST kami, mari kita cuba permintaan sebelum 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 output perintah ini, kita dapat melihat bahawa permintaan itu ditolak dengan 401.

Oleh kerana ini adalah perintah curl , kami tidak akan melihat ralat "Respons for preflight mempunyai kod status HTTP 401 yang tidak valid" dalam output.

Tetapi kita boleh menghasilkan semula kesalahan yang tepat ini dengan membuat aplikasi front-end yang menggunakan API REST kami dari domain yang berbeza dan menjalankannya dalam penyemak imbas.

6. Penyelesaiannya

Kami tidak secara eksplisit mengecualikan permintaan preflight dari kebenaran dalam konfigurasi Spring Security kami . Ingatlah bahawa Spring Security melindungi semua titik akhir secara lalai.

Hasilnya, API kami mengharapkan token kebenaran dalam permintaan PILIHAN juga.

Spring memberikan jalan keluar untuk mengecualikan permintaan PILIHAN dari pemeriksaan kebenaran:

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

Kaedah cors () akan menambahkan CorsFilter yang disediakan Spring ke konteks aplikasi yang seterusnya memotong pemeriksaan kebenaran untuk permintaan PILIHAN.

Sekarang kita dapat menguji aplikasi kita lagi dan melihat bahawa ia berfungsi.

7. Kesimpulannya

Dalam artikel pendek ini, kami telah mempelajari cara memperbaiki ralat "Respons untuk preflight mempunyai kod status HTTP 401 yang tidak valid" yang dihubungkan dengan Spring Security dan permintaan lintas asal.

Perhatikan bahawa, dengan contoh, klien dan API harus berjalan di domain atau port yang berlainan untuk mencipta masalah. Sebagai contoh, kami dapat memetakan nama host lalai ke klien dan alamat IP mesin ke REST API kami ketika berjalan di mesin tempatan.

Seperti biasa, contoh yang ditunjukkan dalam tutorial ini boleh didapati di Github.