Spring WebFlux Kotlin OAuth2 CORS
Spring WebFlux Kotlin OAuth2 CORS
所以这是配置...
我有 localhost:8080 作为我的后端,localhost:3000 作为我的前端。后端的身份验证仅通过 OAuth2 处理。基本上,前端用户单击“使用 Spotify 登录”,被重定向到处理 OAuth2 的后端,然后重定向回前端。所有后续请求都来自前端到后端。 (前端在 Next.JS 顺便说一句)
这是我的问题...
如果我未通过身份验证,对我后端的任何请求都会引发 CORS 错误。 (如果我通过身份验证,它会按预期工作)。所以 GET /users/{id},虽然没有登录,returns CORS,而不是普通的 401。这没关系,因为我可以解决它,但是现在我不能发出 PUT 请求由于 CORS 而导致的端点,即使在登录时......我已经尝试过 @CrossOrigin 注释,但这没有帮助。我还在 SecurityConfig 中尝试了 .cors().disable()
,但是我 仍然 在前端抛出 CORS 错误...
这是我用于 Security/WebFlux 的内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<version>5.4.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.4.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
这是我的 CorsConfig:
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter("/*")
class CorsConfig: WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
.allowCredentials(true)
super.addCorsMappings(registry)
}
}
这是我的安全配置:
@EnableWebFluxSecurity
class SecurityConfig(
@Qualifier("globalErrorHandler")
private val exceptionHandler: WebExceptionHandler,
private val authenticationFailureHandler: ServerAuthenticationFailureHandler,
private val authenticationSuccessHandler: AuthenticationSuccessHandler,
private val authorizationRequestResolver: ServerOAuth2AuthorizationRequestResolver,
private val logoutSuccessHandler: LogoutSuccessHandler
) {
@Bean
fun securityFilterChain(
httpSecurity: ServerHttpSecurity
): SecurityWebFilterChain = httpSecurity
.authorizeExchange()
.pathMatchers("/login", "/register", "/logout").permitAll()
.anyExchange().authenticated()
.and()
.cors().disable()
.exceptionHandling(::withConfiguration)
.oauth2Login(::withConfiguration)
.logout(::withConfiguration)
.csrf().disable()
.build()
fun withConfiguration(spec: ServerHttpSecurity.ExceptionHandlingSpec): Unit =
spec.accessDeniedHandler(exceptionHandler::handle)
.authenticationEntryPoint(exceptionHandler::handle)
.run {}
fun withConfiguration(spec: ServerHttpSecurity.OAuth2LoginSpec): Unit =
spec.authenticationFailureHandler(authenticationFailureHandler)
.authenticationSuccessHandler(authenticationSuccessHandler)
.authorizationRequestResolver(authorizationRequestResolver)
.run { }
fun withConfiguration(spec: ServerHttpSecurity.LogoutSpec): Unit =
spec.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.run { }
}
如果您需要更多信息,请随时询问。
这是我的解决方案,我需要添加:
fun corsConfigurationSource(): CorsConfigurationSource {
val cors = CorsConfiguration()
cors.allowedOrigins = List.of("*")
cors.allowedMethods = List.of("*")
cors.allowedHeaders = List.of("*")
cors.allowCredentials = true
cors.maxAge = 3600L
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", cors)
return source
}
然后,在我的 SecurityWebFilterChain 中,我需要让 Cors 使用我的配置:
@Bean
fun securityFilterChain(
httpSecurity: ServerHttpSecurity
): SecurityWebFilterChain = httpSecurity
.cors(::withConfiguration)
.csrf().disable()
.authorizeExchange()
.pathMatchers("/login", "/register", "/logout").permitAll()
.anyExchange().authenticated()
.and()
.exceptionHandling(::withConfiguration)
.oauth2Login(::withConfiguration)
.logout(::withConfiguration)
.build()
并且 ::withConfiguration 解析为:
fun withConfiguration(spec: ServerHttpSecurity.CorsSpec): Unit =
spec.configurationSource(corsConfigurationSource())
.run { }
所以这是配置...
我有 localhost:8080 作为我的后端,localhost:3000 作为我的前端。后端的身份验证仅通过 OAuth2 处理。基本上,前端用户单击“使用 Spotify 登录”,被重定向到处理 OAuth2 的后端,然后重定向回前端。所有后续请求都来自前端到后端。 (前端在 Next.JS 顺便说一句)
这是我的问题...
如果我未通过身份验证,对我后端的任何请求都会引发 CORS 错误。 (如果我通过身份验证,它会按预期工作)。所以 GET /users/{id},虽然没有登录,returns CORS,而不是普通的 401。这没关系,因为我可以解决它,但是现在我不能发出 PUT 请求由于 CORS 而导致的端点,即使在登录时......我已经尝试过 @CrossOrigin 注释,但这没有帮助。我还在 SecurityConfig 中尝试了 .cors().disable()
,但是我 仍然 在前端抛出 CORS 错误...
这是我用于 Security/WebFlux 的内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<version>5.4.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.4.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
这是我的 CorsConfig:
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter("/*")
class CorsConfig: WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
.allowCredentials(true)
super.addCorsMappings(registry)
}
}
这是我的安全配置:
@EnableWebFluxSecurity
class SecurityConfig(
@Qualifier("globalErrorHandler")
private val exceptionHandler: WebExceptionHandler,
private val authenticationFailureHandler: ServerAuthenticationFailureHandler,
private val authenticationSuccessHandler: AuthenticationSuccessHandler,
private val authorizationRequestResolver: ServerOAuth2AuthorizationRequestResolver,
private val logoutSuccessHandler: LogoutSuccessHandler
) {
@Bean
fun securityFilterChain(
httpSecurity: ServerHttpSecurity
): SecurityWebFilterChain = httpSecurity
.authorizeExchange()
.pathMatchers("/login", "/register", "/logout").permitAll()
.anyExchange().authenticated()
.and()
.cors().disable()
.exceptionHandling(::withConfiguration)
.oauth2Login(::withConfiguration)
.logout(::withConfiguration)
.csrf().disable()
.build()
fun withConfiguration(spec: ServerHttpSecurity.ExceptionHandlingSpec): Unit =
spec.accessDeniedHandler(exceptionHandler::handle)
.authenticationEntryPoint(exceptionHandler::handle)
.run {}
fun withConfiguration(spec: ServerHttpSecurity.OAuth2LoginSpec): Unit =
spec.authenticationFailureHandler(authenticationFailureHandler)
.authenticationSuccessHandler(authenticationSuccessHandler)
.authorizationRequestResolver(authorizationRequestResolver)
.run { }
fun withConfiguration(spec: ServerHttpSecurity.LogoutSpec): Unit =
spec.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.run { }
}
如果您需要更多信息,请随时询问。
这是我的解决方案,我需要添加:
fun corsConfigurationSource(): CorsConfigurationSource {
val cors = CorsConfiguration()
cors.allowedOrigins = List.of("*")
cors.allowedMethods = List.of("*")
cors.allowedHeaders = List.of("*")
cors.allowCredentials = true
cors.maxAge = 3600L
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", cors)
return source
}
然后,在我的 SecurityWebFilterChain 中,我需要让 Cors 使用我的配置:
@Bean
fun securityFilterChain(
httpSecurity: ServerHttpSecurity
): SecurityWebFilterChain = httpSecurity
.cors(::withConfiguration)
.csrf().disable()
.authorizeExchange()
.pathMatchers("/login", "/register", "/logout").permitAll()
.anyExchange().authenticated()
.and()
.exceptionHandling(::withConfiguration)
.oauth2Login(::withConfiguration)
.logout(::withConfiguration)
.build()
并且 ::withConfiguration 解析为:
fun withConfiguration(spec: ServerHttpSecurity.CorsSpec): Unit =
spec.configurationSource(corsConfigurationSource())
.run { }