如果http://a2a-web:80/hello.html這個網頁呼叫http://a2a-web:80/hi.html是可以的,但呼叫http://a2a-api:8081/v1/ap1會被瀏覽器阻擋,這違反瀏覽器預設的同源政策。
URL的組成分別是協議(http、https)、域名(localhost、IP)、port及URI,比如:http:// a2a-web:80/echo,前三者相同就是同源,其中一個不同就觸發CORS(Cross-Origin Resource Sharing,跨來源資源共用)。
事實上瀏覽器發現請求是CORS不是直接擋,流程就像來客到a2a-api公司門口請櫃台窗口通報,櫃台識別來客是a2a-web這家公司是允許名單就讓它呼叫API,不在允許名單裡,瀏覽器就充當警衛的角色請來客走人。
Spring-Security是Spring家族的資安單位,Spring Boot當然直接引用最快。CORS允許清單就設在.container檔,以逗號分隔來源。例:vi .config/containers/systemd/a2a-api.container
[Container]
# 略...
Environment=platform.security.cors.allowed-origins=http://a2a-web:80,https://a2a-proxy:8443
而在Spring Boot專案增加SecurityConfig來讀platform.security.cors.allowed-origins參數。
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
@Configuration
@EnableWebSecurity // 1.生效Spring-Security
@ConfigurationProperties(prefix = "platform.security.cors") // 2.讀環境變數
public class SecurityConfig {
private List<String> allowedOrigins; // 3. 從環境變數載入來源清單
private CorsConfigurationSource createCorsConfig() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(allowedOrigins); // 4. 設定允許來源清單
config.setAllowedHeaders(List.of("*"));
config.setAllowedMethods(List.of("*"));
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults())
.authorizeHttpRequests(request -> request
.anyRequest().authenticated()
)
// 5. 設定CORS生效
.cors(cors -> cors
.configurationSource(createCorsConfig())
)
.build();
}
}
platform.security.cors.allowed-origins
platform.security.cors.allowedOrigins