CORS dengan Spring

1. Ikhtisar

Di browser modern apa pun, Cross-Origin Resource Sharing (CORS) adalah spesifikasi yang relevan dengan munculnya klien HTML5 dan JS yang menggunakan data melalui REST API.

Dalam banyak kasus, host yang melayani JS (misalnya, example.com ) berbeda dari host yang menyajikan data (misalnya, api.example.com ). Dalam kasus seperti itu, CORS memungkinkan komunikasi lintas domain.

Spring menyediakan dukungan kelas satu untuk CORS, menawarkan cara yang mudah dan kuat untuk mengonfigurasinya di aplikasi web Spring atau Spring Boot.

2. Metode Pengontrol Konfigurasi CORS

Mengaktifkan CORS sangat mudah - cukup tambahkan anotasi @CrossOrigin .

Kami dapat menerapkan ini dengan beberapa cara berbeda.

2.1. @CrossOrigin pada Metode Penangan Beranotasi @ RequestMapping-

@RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @RequestMapping(method = RequestMethod.GET, path = "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

Pada contoh di atas, kami hanya mengaktifkan CORS untuk metode retve () . Kita dapat melihat bahwa kita tidak menyetel konfigurasi apa pun untuk anotasi @CrossOrigin , jadi ia menggunakan default:

  • Semua asal diperbolehkan
  • Metode HTTP yang diizinkan adalah yang ditentukan dalam anotasi @RequestMapping (untuk contoh ini adalah GET)
  • Waktu respons preflight di-cache ( maxAge) adalah 30 menit

2.2. @CrossOrigin di Controller

@CrossOrigin(origins = "//example.com", maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @RequestMapping(method = RequestMethod.GET, path = "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

Kali ini, kami menambahkan @CrossOrigin di level kelas. Akibatnya, metode retve () dan remove () telah mengaktifkannya. Kita dapat menyesuaikan konfigurasi dengan menentukan nilai salah satu atribut anotasi: origins , methods , allowHeaders , eksposHeaders , allowCredentials, atau maxAge.

2.3. @CrossOrigin tentang Metode Pengontrol dan Penangan

@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("//example.com") @RequestMapping(method = RequestMethod.GET, "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

Spring akan menggabungkan atribut dari kedua anotasi untuk membuat konfigurasi CORS gabungan.

Dalam contoh ini, kedua metode akan memiliki maxAge 3600 detik, metode remove () akan mengizinkan semua asal, tetapi metode mengambil () hanya akan mengizinkan asal dari //example.com.

3. Konfigurasi CORS Global

Sebagai alternatif dari konfigurasi berbasis anotasi halus, Spring memungkinkan kita menentukan beberapa konfigurasi CORS global dari pengontrol Anda. Ini mirip dengan menggunakan solusi berbasis Filter tetapi dapat dideklarasikan dalam Spring MVC dan dikombinasikan dengan konfigurasi @CrossOrigin yang sangat halus .

Secara default, semua asal dan metode GET, HEAD, dan POST diizinkan.

3.1. JavaConfig

@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }

Contoh di atas memungkinkan permintaan CORS dari asal mana pun ke titik akhir mana pun dalam aplikasi.

Jika kita ingin menguncinya sedikit lagi, metode registry.addMapping mengembalikan objek CorsRegistration , yang dapat kita gunakan untuk konfigurasi tambahan. Ada juga metode allowOrigins yang memungkinkan kita menentukan larik asal yang diizinkan. Ini dapat berguna jika kita perlu memuat larik ini dari sumber eksternal saat runtime.

Selain itu, ada juga allowMethods , allowHeaders , eksposHeaders , maxAge , dan allowCredentials yang dapat kita gunakan untuk menyetel header respons dan opsi penyesuaian.

3.2. XML Namespace

Konfigurasi XML minimal ini memungkinkan CORS pada pola jalur / ** dengan properti default yang sama dengan yang JavaConfig:

Ini juga memungkinkan untuk mendeklarasikan beberapa pemetaan CORS dengan properti yang disesuaikan:

4. CORS dengan Spring Security

Jika kami menggunakan Keamanan Musim Semi dalam proyek kami, kami harus mengambil langkah ekstra untuk memastikannya berfungsi dengan baik dengan CORS. Karena CORS harus diproses terlebih dahulu. Jika tidak, Keamanan Musim Semi akan menolak permintaan sebelum mencapai MVC Musim Semi.

Untungnya, Spring Security menyediakan solusi out-of-the-box:

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

Artikel ini menjelaskannya lebih detail.

5. Bagaimana Ini Bekerja

CORS requests are automatically dispatched to the various registered HandlerMappings. They handle CORS preflight requests and intercept CORS simple and actual requests using a CorsProcessor implementation (DefaultCorsProcessor by default) to add the relevant CORS response headers (such as Access-Control-Allow-Origin).

CorsConfiguration allows us to specify how the CORS requests should be processed: allowed origins, headers, and methods, among others. We may provide it in various ways:

  • AbstractHandlerMapping#setCorsConfiguration() allows one to specify a Map with several CorsConfigurations mapped onto path patterns such as /api/**
  • Subclasses may provide their own CorsConfiguration by overriding the AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest) method
  • Handlers may implement the CorsConfigurationSource interface (like ResourceHttpRequestHandler now does) to provide a CorsConfiguration for each request

6. Conclusion

In this article, we showed how Spring provides support for enabling CORS in our application.

We started with the configuration of the controller. We saw that we only need to add the annotation @CrossOrigin to enable CORS either to one particular method or the entire controller.

Akhirnya, kami juga melihat bahwa jika kami ingin mengontrol konfigurasi CORS di luar pengontrol, kami dapat melakukan ini dengan lancar di file konfigurasi - baik menggunakan JavaConfig atau XML.

Kode sumber lengkap untuk contoh tersedia di GitHub.