从前端向 Spring Cloud Gateway 发出请求时出现 CORS 问题

问题描述 投票:0回答:1

我正在开发一个微服务架构,并使用 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 上运行

任何对此的建议将不胜感激!

spring-boot cors spring-boot-security
1个回答
0
投票

在 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。也许他们改变了一些东西。

© www.soinside.com 2019 - 2024. All rights reserved.