CORS trong Spring

11 tháng 09, 2022 - 4937 lượt xem

CORS trong Spring

Người dịch: Trần Ngọc Quân - Học viên lớp Java08
Email liên hệ: quan.tranngoc317@gmail.com
Bài viết gốc: https://www.baeldung.com/spring-cors

1. Tổng quan

Trong các trình duyệt ngày nay, Cross-Origin Resource Sharing (CORS) là kĩ thuật hỗ trợ khi HTML5 và JS client cần truy cập tài nguyên thông qua REST APIs.
Thông thường, host chạy JS ( VD: example.com) khác biệt với host chạy phần server dữ liệu (VD: api.example.com). Trong trường hợp này, CORS cho phép giao tiếp giữa các domain khác nhau (cross-domain) hoạt động.
Spring ưu tiên hỗ trợ CORS một cách tối ưu nhất, cung cấp phương tiện đơn giản và hiệu quả để thiết lập CORS trong các ứng dụng Spring hoặc Spring Boot

2. Thiết lập CORS trong controller method

Kích hoạt CORS rất đơn giản – chỉ cần thêm annotation @CrossOrigin.
Ta có thể triển khai theo một số cách khác nhau.

2.1. @CrossOrigin trong phương thức được đánh dấu @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) {
        // ...
    }
}

Trong ví dụ trên, ta chỉ kích hoạt CORS cho phương thức retrieve(). Khi không có thiết lập cụ thể cho @CrossOrigin annotation, các chỉ tiêu mặc định sẽ được áp dụng:

  • Cho phép truy cập từ mọi origin
  • Hàm HTTP request được phép truy cập được là hàm được nhắc đến bên trong annotation @RequestMapping (trong ví dụ này là GET)
  • Thời gian truy vấn preflight phản hồi được cache (maxAge) là 30 phút.

2.2. @CrossOrigin trong Controller

@CrossOrigin(origins = "http://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) {
        // ...
    }
}

Lần này, ta thêm @CrossOrigin vào cấp Class. Do vậy, cả phương thức retrieve() và remove() đều cho phép CORS. Ta cũng có thể tùy biến thiết lập bằng các annotation attribute: origins, methods, allowedHeaders, exposedHeaders, allowCredentials hoặc maxAge.

2.3. @CrossOrigin cho cả class và phương thức của controller

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin("http://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 sẽ kết hợp các thuộc tính từ cả hai annotation để tạo ra một cấu hình CORS.
Như ở đây, cả 2 phương thức retrieve() và remove() đều có maxAge là 3600 giây, tuy nhiên phương thức remove() cho phép truy cập từ mọi origin, trong khi phương thức retrieve chỉ cho phép truy cập từ http://example.com

3. Cấu hình Global CORS

Một giải pháp khác so với cấu hình bằng annotation, Spring cho phép ta định nghĩa cấu hình global CORS bên ngoài controller. Cách này giống với việc sử dụng 1 bộ lọc Filter nhưng có thể khai báo trong Spring MVC và kết hợp với cấu hình @CrossOrigin.
Mặc định, tất cả các origin và hàm GET, HEAD, POST được cho phép hoạt động.

3.1. JavaConfig

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

Ví dụ trên cho phép các CORS request từ bất cứ origin nào truy cập đến toàn bộ tài nguyên trong ứng dụng. Để hiểu rõ hơn, phương thức registry.addMapping trả về một đối tượng CosRegistration mà ta có thể sử dụng để thêm cấu hình. Ngoài ra còn có phương thức allowedOrigins cho phép ta xác định 1 mảng những origin nào được phép truy cập. Chức năng này sẽ hữu ích khi ta cần tải mảng đó từ tài nguyên bên ngoài trong giai đoạn runtime.
Bên cạnh đó, ta còn có thể sử dụng một số phương thức khác như allowedMethods, allowedHeaders, exposedHeaders, maxAge và allowCredentials để cài đặt response header và các lựa chọn tùy biến.

3.2. XML Namespace

Cấu hình XML tối giản này cho phép CORS trong đường dẫn /** với các đặc tính mặc định giống với khi sử dụng JavaConfig:

<mvc:cors>
    <mvc:mapping path="/**" />
</mvc:cors>

Ta cũng có thể khai báo nhiều CORS mappings bằng các tùy biến properties

<mvc:cors>

    <mvc:mapping path="/api/**"
        allowed-origins="http://domain1.com, http://domain2.com"
        allowed-methods="GET, PUT"
        allowed-headers="header1, header2, header3"
        exposed-headers="header1, header2" allow-credentials="false"
        max-age="123" />

    <mvc:mapping path="/resources/**"
        allowed-origins="http://domain1.com" />

</mvc:cors>

4. CORS với Spring Security

Nếu chương trình có sử dụng Spring Security, ta bắt buộc phải thêm một bước thiết lập để đảm bảo CORS có thể hoạt động tốt. Nguyên nhân là do CORS cần phải được xử lý trước nếu không Spring Security sẽ từ chối request trước khi được gửi đến Spring MVC
Spring Security cung cấp một giải pháp đơn giản như ví dụ bên dưới.

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}
  1. Cách hoạt động
    Các CORS request được tự động gửi đến các HandlerMappings đã được thiết lập. Chúng xử lý các CORS preflight request và các request thực sử dụng trình triển khai CorsProcessor (mặc định là DefaultCorsProcessor) để thêm CORS response header thích hợp (như Access-Control-Allow-Origin)
    CorsConfiguration giúp ta xác định cách các CORS request được xử lý, bao gồm cho phép origin, header và phương thức. Ta có thể áp dụng theo các cách khác nhau:
  • AbstractHandlerMapping#setCorsConfiguration() cho phép chỉ định 1 Map với một số CorsConfiguration được map vào cấu trúc đường dẫn như /api/**.
  • Subclass có thể cung cấp CorsConfiguration riêng bằng cách ghi đè phương thức AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest).
  • Các trình handler có thể implement interface CorsConfigurationSource (như ResourceHttpRequestHandler ) để cung cấp CorsConfiguration cho từng request.

6. Tổng kết.

Trong bài viết này, ta đã tìm hiểu cách Spring cung cấp tính năng hỗ trợ CORS trong ứng dụng.
Bắt đầu với cấu hình của controller, ta thấy rằng chỉ cần thêm annotation @CrossOrigin là có thể kích hoạt CORS của một phương thức cụ thể hoặc toàn bộ controller.
Ngoài ra, ta đã biết rằng có thể thiết lập cấu hình CORS bên ngoài controller bằng cách sử dụng các file cài đặt như JavaConfig hoặc XML

Bình luận

avatar
Trịnh Minh Cường 2022-09-12 04:30:51.956742 +0000 UTC

Em viết rất hay. Thầy đọc thích. Cảm ơn đã đóng góp những bài viết chất lượng

Avatar
avatar
vĩnh đặng văn 2022-11-01 10:49:49.137583 +0000 UTC

thanks tác giả, bài viết rất dễ hiểu và chi tiết

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  +1 Thích
+1