package com.gw.boot.config; import org.apache.commons.net.util.SubnetUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.InetAddress; import java.net.URI; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.LinkedList; @Configuration public class CrosConfig { private static final String MAX_AGE = "18000L"; private static Logger logger = LoggerFactory.getLogger(CrosConfig.class); private AllowCorsUrlProperties allowCorsUrlProperties; public CrosConfig(AllowCorsUrlProperties allowCorsUrlProperties) { this.allowCorsUrlProperties = allowCorsUrlProperties; } public static boolean isIPInRange(String ipAddress, String cidrNotation) { try { InetAddress ip = InetAddress.getByName(ipAddress); SubnetUtils subnetUtils = new SubnetUtils(cidrNotation); subnetUtils.setInclusiveHostCount(true); return subnetUtils.getInfo().isInRange(ip.getHostAddress()); } catch (UnknownHostException e) { // 处理异常情况 e.printStackTrace(); } return false; } @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest req = ctx.getRequest(); // 原始的 String origin = req.getHeaders().getOrigin(); logger.info("corsFilter origin:[{}]", origin); URI uri = req.getURI(); // 真实的 String actual = uri.toString(); logger.info("corsFilter actual:[{}]", actual); // 判断协议、ip、端口,如果都相同,直接透传,不相同增加响应头参数。 if (CorsUtils.isCorsRequest(req)) { // 默认全部不允许 if (checkAllowCorsRequest(origin)) { logger.error("请求的Origin值[{}]不在允许范围内", origin); return unauthorized(ctx, "请求的origin值不在允许范围内"); } HttpHeaders reqHeaders = req.getHeaders(); ServerHttpResponse resp = ctx.getResponse(); // HttpMethod reqMethod = reqHeaders.getAccessControlRequestMethod(); HttpHeaders headers = resp.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, reqHeaders.getOrigin()); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, " + "Cache-Control, Expires, Content-Type, X-E4M-With,userId,token"); 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 (req.getMethod() == HttpMethod.OPTIONS) { resp.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter() { return new HiddenHttpMethodFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange); } }; } private boolean checkAllowCorsRequest(String origin) { logger.info("request origin :{}", origin); // 默认全部不允许 boolean flag = true; if (null == origin) { return false; } try { // origin截取IP String ipAddress = origin.substring(origin.indexOf("//") + 2, origin.lastIndexOf(":")); LinkedList<String> urls = allowCorsUrlProperties.getUrls(); if (null != allowCorsUrlProperties && null != urls) { for (String allowOriginUrl : urls) { logger.info("allowOriginUrl :{}", allowOriginUrl); // boolean isInRange = isIPInRange(ipAddress, cidrNotation); if (isIPInRange(ipAddress, allowOriginUrl)) { flag = false; break; } } } } catch (Exception e) { logger.error("checkAllowCorsRequest error", e); } return flag; } private Mono<Void> unauthorized(ServerWebExchange exchange, String message) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8"); DataBuffer buffer = exchange.getResponse() .bufferFactory().wrap(null == message ? HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes() : message.getBytes(StandardCharsets.UTF_8)); return exchange.getResponse().writeWith(Flux.just(buffer)); } }
[Springboot] Cros 跨域过滤
最新推荐文章于 2025-03-10 23:49:12 发布