我正在开发一个微服务架构,并使用 Spring Cloud Gateway 作为 API 网关。
当我通过 Postman 和 Swagger UI 向端口 8090 上的网关发出请求时,一切正常,并且我收到 200 OK 响应。但是,当我尝试从前端(在端口 3000 上运行)发出相同的请求时,我收到了 CORS 错误:
从源“http://localhost:3000”访问“http://localhost:8090/api/v1/accounts/login”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。
我已在下游服务中而不是 API 网关中设置 CORS 配置。这是我在下游服务之一中的设置:
package com.example.e_commerce.helper.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.CorsConfigurationSource
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
@Configuration
class CorsConfig {
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration().apply {
allowedOrigins = listOf(
"http://localhost:3000",
"http://192.168.1.35:3000",
"http://localhost:8090",
"http://127.0.0.1:8090",
)
allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
allowCredentials = true
allowedHeaders = listOf("*")
}
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", configuration)
return source
}
}
package com.example.e_commerce.authservice.config
import com.example.e_commerce.authservice.service.UserService
import com.example.e_commerce.helper.config.CorsConfig
import com.example.e_commerce.helper.config.JwtConfig
import com.example.e_commerce.helper.exceptions.GlobalAccessDeniedHandler
import com.example.e_commerce.helper.exceptions.GlobalAuthenticationEntrypoint
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.ProviderManager
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.web.SecurityFilterChain
@Configuration
@EnableWebSecurity
class SecurityConfig(
private val globalAccessDeniedHandler: GlobalAccessDeniedHandler,
private val globalAuthenticationEntrypoint: GlobalAuthenticationEntrypoint,
private val corsConfig: CorsConfig,
private val jwtConfig: JwtConfig,
) {
private val whiteList: Array<String> = arrayOf(
"/swagger-ui.html",
"/swagger-ui/**",
"/aggregate/*/v3/api-docs",
"/v3/api-docs/**",
"/swagger-resources/**",
"/swagger-resources",
"/webjars/**",
"/configuration/**"
)
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
return http
.csrf { csrf -> csrf.disable() }
.authorizeHttpRequests { requests ->
requests
.requestMatchers(*whiteList).permitAll()
.requestMatchers("/api/v1/users/deactivate/**").hasAnyRole("Admin")
.requestMatchers("/api/v1/accounts/login", "/api/v1/accounts/signup").permitAll()
.requestMatchers("/api/v1/users/exists/**").permitAll()
.anyRequest().authenticated()
}
.exceptionHandling {
it.accessDeniedHandler(globalAccessDeniedHandler)
it.authenticationEntryPoint(globalAuthenticationEntrypoint)
}
.oauth2ResourceServer { oauth2 ->
oauth2.jwt { jwt ->
jwt.decoder(jwtConfig.jwtDecoder())
jwt.jwtAuthenticationConverter(jwtConfig.jwtAuthenticationConverter())
}
}
.sessionManagement { session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.cors { cors -> cors.configurationSource(corsConfig.corsConfigurationSource()) }
.build()
}
@Bean
fun authenticationManager(userService: UserService): AuthenticationManager {
val daoAuthenticationProvider = DaoAuthenticationProvider().apply {
setUserDetailsService(userService)
setPasswordEncoder(BCryptPasswordEncoder())
}
return ProviderManager(daoAuthenticationProvider)
}
}
我想知道仅在下游服务中配置 CORS 是否是正确的方法,或者是否应该在 API 网关上处理。
如何解决此问题并允许通过 API 网关从我的前端发出 CORS 请求?
附加信息:
Spring Boot版本:3.3.4 API网关正在端口8090上运行 前端正在 localhost:3000 上运行
任何对此的建议将不胜感激!
在 SpringBoot 3.3.4 中:遇到同样的问题,Postman 常规 GET/POST 调用以 200 OK 响应结束,但前端应用程序 OPTIONS 调用收到 401 CORS 错误。我特别允许在我的 SecurityFilterChain 中进行无需身份验证的选项,如下所示:
http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(
authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.requestMatchers(HttpMethod.OPTIONS)
.permitAll().anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
请注意,我不必为 Spring 3.3.1 制作这个特殊的选项 PermitAll。也许他们改变了一些东西。