[Springboot] Cros 跨域过滤

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));
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值