|
|
@ -1,15 +1,29 @@ |
|
|
|
/** |
|
|
|
* Copyright (c) 2018 人人开源 All rights reserved. |
|
|
|
* |
|
|
|
* <p> |
|
|
|
* https://www.renren.io
|
|
|
|
* |
|
|
|
* <p> |
|
|
|
* 版权所有,侵权必究! |
|
|
|
*/ |
|
|
|
|
|
|
|
package com.epmet.config; |
|
|
|
|
|
|
|
import com.epmet.bean.CorsConfigCache; |
|
|
|
import com.epmet.commons.tools.constant.ServiceConstant; |
|
|
|
import com.epmet.commons.tools.exception.EpmetErrorCode; |
|
|
|
import com.epmet.commons.tools.exception.ExceptionUtils; |
|
|
|
import com.epmet.commons.tools.feign.ResultDataResolver; |
|
|
|
import com.epmet.commons.tools.redis.RedisKeys; |
|
|
|
import com.epmet.dto.result.CorsConfigResultDTO; |
|
|
|
import com.epmet.feign.EpmetAdminOpenFeignClient; |
|
|
|
import org.apache.commons.collections4.CollectionUtils; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.context.annotation.Bean; |
|
|
|
import org.springframework.context.annotation.Configuration; |
|
|
|
import org.springframework.data.redis.core.HashOperations; |
|
|
|
import org.springframework.data.redis.core.RedisTemplate; |
|
|
|
import org.springframework.http.HttpHeaders; |
|
|
|
import org.springframework.http.HttpMethod; |
|
|
|
import org.springframework.http.HttpStatus; |
|
|
@ -21,6 +35,11 @@ import org.springframework.web.server.WebFilter; |
|
|
|
import org.springframework.web.server.WebFilterChain; |
|
|
|
import reactor.core.publisher.Mono; |
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
/** |
|
|
|
* Cors跨域 |
|
|
|
* |
|
|
@ -29,33 +48,101 @@ import reactor.core.publisher.Mono; |
|
|
|
*/ |
|
|
|
@Configuration |
|
|
|
public class CorsConfig { |
|
|
|
private static final String MAX_AGE = "18000L"; |
|
|
|
|
|
|
|
@Bean |
|
|
|
public WebFilter corsFilter() { |
|
|
|
return (ServerWebExchange ctx, WebFilterChain chain) -> { |
|
|
|
ServerHttpRequest request = ctx.getRequest(); |
|
|
|
if (!CorsUtils.isCorsRequest(request)) { |
|
|
|
return chain.filter(ctx); |
|
|
|
} |
|
|
|
HttpHeaders requestHeaders = request.getHeaders(); |
|
|
|
ServerHttpResponse response = ctx.getResponse(); |
|
|
|
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); |
|
|
|
HttpHeaders headers = response.getHeaders(); |
|
|
|
return new EpmetWebFilter(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @Description 用于CORS等操作的判断 |
|
|
|
* @return |
|
|
|
* @author wxz |
|
|
|
* @date 2021.06.25 10:42 |
|
|
|
*/ |
|
|
|
class EpmetWebFilter implements WebFilter, ResultDataResolver { |
|
|
|
|
|
|
|
private static final String MAX_AGE = "18000L"; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private EpmetAdminOpenFeignClient adminOpenFeignClient; |
|
|
|
|
|
|
|
@Resource |
|
|
|
private RedisTemplate<String, CorsConfigCache> redisTemplate; |
|
|
|
|
|
|
|
private Logger logger = LoggerFactory.getLogger(getClass()); |
|
|
|
|
|
|
|
@Override |
|
|
|
public Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) { |
|
|
|
ServerHttpRequest request = ctx.getRequest(); |
|
|
|
if (!CorsUtils.isCorsRequest(request)) { |
|
|
|
return chain.filter(ctx); |
|
|
|
} |
|
|
|
HttpHeaders requestHeaders = request.getHeaders(); |
|
|
|
ServerHttpResponse response = ctx.getResponse(); |
|
|
|
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); |
|
|
|
HttpHeaders headers = response.getHeaders(); |
|
|
|
if (isAllowed(requestHeaders.getOrigin())) { |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); |
|
|
|
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); |
|
|
|
if (requestMethod != null) { |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); |
|
|
|
} |
|
|
|
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); |
|
|
|
if (requestMethod != null) { |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); |
|
|
|
} |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); |
|
|
|
if (request.getMethod() == HttpMethod.OPTIONS) { |
|
|
|
response.setStatusCode(HttpStatus.OK); |
|
|
|
return Mono.empty(); |
|
|
|
} |
|
|
|
return chain.filter(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @Description 是否允许跨域 |
|
|
|
* @return |
|
|
|
* @author wxz |
|
|
|
* @date 2021.06.25 10:43 |
|
|
|
*/ |
|
|
|
private Boolean isAllowed(String origin) { |
|
|
|
HashOperations<String, String, List<String>> ope = redisTemplate.opsForHash(); |
|
|
|
Map<String, List<String>> configMap = ope.entries(RedisKeys.getCorsConfigKey()); |
|
|
|
|
|
|
|
if (configMap == null || configMap.size() == 0) { |
|
|
|
List<CorsConfigResultDTO> data = null; |
|
|
|
try { |
|
|
|
data = getResultDataOrThrowsException( |
|
|
|
adminOpenFeignClient.list(), |
|
|
|
ServiceConstant.EPMET_ADMIN_SERVER, |
|
|
|
EpmetErrorCode.SERVER_ERROR.getCode(), |
|
|
|
"调用Admin服务查询Cors配置失败"); |
|
|
|
} catch (Exception e) { |
|
|
|
logger.error("调用Admin服务查询Cors配置失败"); |
|
|
|
} |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); |
|
|
|
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); |
|
|
|
if (request.getMethod() == HttpMethod.OPTIONS) { |
|
|
|
response.setStatusCode(HttpStatus.OK); |
|
|
|
return Mono.empty(); |
|
|
|
|
|
|
|
// 将origin集合
|
|
|
|
List<String> origins = data.stream() |
|
|
|
.filter((c) -> HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN.equals(c.getHeaderType())) |
|
|
|
.map((c) -> c.getHeaderValue()) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
try { |
|
|
|
configMap.put(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origins); |
|
|
|
ope.putAll(RedisKeys.getCorsConfigKey(), configMap); |
|
|
|
} catch (Exception e) { |
|
|
|
logger.error(String.format("gateway缓存跨域配置出错:%s", ExceptionUtils.getErrorStackTrace(e))); |
|
|
|
} |
|
|
|
return chain.filter(ctx); |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
List<String> accessControlAllowOrigins = configMap.get(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN); |
|
|
|
if (CollectionUtils.isEmpty(accessControlAllowOrigins)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (accessControlAllowOrigins.contains("*")) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
return accessControlAllowOrigins.contains(origin); |
|
|
|
} |
|
|
|
} |