001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.cors.reactive;
018
019import reactor.core.publisher.Mono;
020
021import org.springframework.http.server.reactive.ServerHttpRequest;
022import org.springframework.util.Assert;
023import org.springframework.web.cors.CorsConfiguration;
024import org.springframework.web.server.ServerWebExchange;
025import org.springframework.web.server.WebFilter;
026import org.springframework.web.server.WebFilterChain;
027
028
029/**
030 * {@link WebFilter} that handles CORS preflight requests and intercepts
031 * CORS simple and actual requests thanks to a {@link CorsProcessor} implementation
032 * ({@link DefaultCorsProcessor} by default) in order to add the relevant CORS
033 * response headers (like {@code Access-Control-Allow-Origin}) using the provided
034 * {@link CorsConfigurationSource} (for example an {@link UrlBasedCorsConfigurationSource}
035 * instance.
036 *
037 * <p>This is an alternative to Spring WebFlux Java config CORS configuration,
038 * mostly useful for applications using the functional API.
039 *
040 * @author Sebastien Deleuze
041 * @since 5.0
042 * @see <a href="https://www.w3.org/TR/cors/">CORS W3C recommendation</a>
043 */
044public class CorsWebFilter implements WebFilter {
045
046        private final CorsConfigurationSource configSource;
047
048        private final CorsProcessor processor;
049
050
051        /**
052         * Constructor accepting a {@link CorsConfigurationSource} used by the filter
053         * to find the {@link CorsConfiguration} to use for each incoming request.
054         * @see UrlBasedCorsConfigurationSource
055         */
056        public CorsWebFilter(CorsConfigurationSource configSource) {
057                this(configSource, new DefaultCorsProcessor());
058        }
059
060        /**
061         * Constructor accepting a {@link CorsConfigurationSource} used by the filter
062         * to find the {@link CorsConfiguration} to use for each incoming request and a
063         * custom {@link CorsProcessor} to use to apply the matched
064         * {@link CorsConfiguration} for a request.
065         * @see UrlBasedCorsConfigurationSource
066         */
067        public CorsWebFilter(CorsConfigurationSource configSource, CorsProcessor processor) {
068                Assert.notNull(configSource, "CorsConfigurationSource must not be null");
069                Assert.notNull(processor, "CorsProcessor must not be null");
070                this.configSource = configSource;
071                this.processor = processor;
072        }
073
074
075        @Override
076        public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
077                ServerHttpRequest request = exchange.getRequest();
078                CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(exchange);
079                boolean isValid = this.processor.process(corsConfiguration, exchange);
080                if (!isValid || CorsUtils.isPreFlightRequest(request)) {
081                        return Mono.empty();
082                }
083                return chain.filter(exchange);
084        }
085
086}