Spring Cloud Gateway跨域相关解决方案

  • Post author:
  • Post category:其他




前言

记录

Spring Cloud Gateway

整合

Spring Security



Oauth2

时跨越问题相关解决过程




项目架构

为了不直接暴露

API

及保护服务器,所有访问都需要经过网关,由网关转发请求到服务器及返回服务器的响应

在这里插入图片描述




初遇跨域

跨域其实是很常见的问题,在

Spring

中可以简单的写个

@CrossOrigin

或者全局拦截器之类的解决掉,但在

Spring Cloud Gateway

中这行不通,写注解等方式在路由转发时还是会跨域

在这里插入图片描述


官方文档

给出相关跨域配置(实测不好用)

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

不过你可以轻易的通过Google搜索到如下代码

import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Bean
public CorsWebFilter corsFilter() {
	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
	CorsConfiguration config = new CorsConfiguration();
	config.addAllowedOrigin("*");
	config.setAllowCredentials(true);
	config.addAllowedHeader("*");
	config.addAllowedMethod("*");
	source.registerCorsConfiguration("/**", config);

	return new CorsWebFilter(source);
}

简单的在启动类上或者其他什么地方加上后会发现跨域解决了




架构升级

在原系统中加个

Bean

就解决了跨域问题,现在为了进行

权限控制

我们需要给系统加上

Oauth2

认证

图源-https://spring.io/blog/2019/08/16/securing-services-with-spring-cloud-gateway

当用户访问敏感资源时需要用户登录并授权(类似第三方登录)

在这里插入图片描述

在这里插入图片描述

这时候

Gateway

既是网关也是

Oauth2

中的

Client

角色,用户授予

Gateway

某些权限可以访问用户相关资源,

Gateway

在获得授权后从

UAA

中获得

Token

。用户请求到达

Gateway

后每次转发都会带上

Token



Resource Server



Token

进行验证并作出响应。


Gateway

项目相关依赖如下:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.12.RELEASE</version>
	<relativePath/>
</parent>


<properties>
	<java.version>1.8</java.version>
	<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-oauth2-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-gateway</artifactId>
	</dependency>
</dependencies>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>



再遇跨域

在引入

Oauth2



Security

相关依赖后发现又跨域了

在这里插入图片描述

可以发现

GET

请求正常,但

POST



非简单请求

遇到

Preflight

问题,这个问题的一般思路是拦截

OPTION

请求直接返回

200

以便后续真正的请求顺利发起

其实这个问题是花时间最多的,期间写过

Gateway

的拦截器、

Security

的拦截器、全局拦截器、

Webflux

配置和全局配置等等,没一个能打的

然后考虑到是引入

Oauth2



Security

相关依赖后才使原来的

Bean

失效,那可能是优先级的原因,请求在进入定义的

Filter

前就别拦截了。于是尝试提高

Bean

的优先级,但还是无果

最后在审查

Bean

代码时发现在创建

CorsWebFilter

时需要

ConfigurationSource

作为入参,那么拦截了请求的

Filter

会不会也需要相应的

ConfigurationSource

呢?于是将

ConfigurationSource

单独作为

Bean

创建,结果成功解决

Preflight

问题

@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
	CorsConfiguration config = new CorsConfiguration();
	config.addAllowedOrigin("*");
	config.setAllowCredentials(true);
	config.addAllowedHeader("*");
	config.addAllowedMethod("*");
	source.registerCorsConfiguration("/**", config);
	return source;
}

解决

Preflight

后又遇到

403

问题

在这里插入图片描述

查看响应

在这里插入图片描述



CSRF

相关,只要关掉就好了

import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
														ReactiveClientRegistrationRepository clientRegistrationRepository) {
	http.oauth2Login();
	http.authorizeExchange().anyExchange().authenticated();
	http.csrf().disable();

	return http.build();
}

至此,跨域问题完全解决




版权声明:本文为sinat_34200786原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。