@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
if(RString.isBlank(AppResource.getProperty("AllowedOrigins"))){
corsConfiguration.addAllowedOrigin("*");
}else{
corsConfiguration.setAllowedOrigins(Arrays.asList(AppResource.getProperty("AllowedOrigins").split(",")));
}
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}
该方法实现了H5跨域功能,目前使用 静态文件读取配置文件并在启动时加载该拦截器
if(RString.isBlank(AppResource.getProperty("AllowedOrigins"))){//如果配置文件没有该数据,则所有页面都能跨域访问
corsConfiguration.addAllowedOrigin("*");
}else{//指定部分域名允许跨域访问
corsConfiguration.setAllowedOrigins(Arrays.asList(AppResource.getProperty("AllowedOrigins").split(",")));
}
该功能也实现了跨域设置,但是问题来了,我想要实时更新允许的域名,该怎么办:
想到了spring boot 安全检测的包 spring-boot-starter-actuator 使用refresh 方法功能
application.properties 启动配置文件 配置文件
#关闭安全校验校验
management.security.enabled=false
#指定访问这些监控方法的端口,与逻辑接口端口分离。
management.port=18016
#指定地址,比如只能通过本机监控
management.address=
#启用shutdown
endpoints.shutdown.enabled=true
但是使用 refresh功能刷新程序后,允许跨域的域名没有发生改变
查询corsFilter 源码分析后发现
new CorsFilter(source)
源码
* Copyright 2002-2016 the original author or authors.
package org.springframework.web.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.Assert;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsProcessor;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.DefaultCorsProcessor;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
/**
* {@link javax.servlet.Filter} that handles CORS preflight requests and intercepts
* CORS simple and actual requests thanks to a {@link CorsProcessor} implementation
* ({@link DefaultCorsProcessor} by default) in order to add the relevant CORS
* response headers (like {@code Access-Control-Allow-Origin}) using the provided
* {@link CorsConfigurationSource} (for example an {@link UrlBasedCorsConfigurationSource}
* instance.
*
* This is an alternative to Spring MVC Java config and XML namespace CORS configuration,
* useful for applications depending only on spring-web (not on spring-webmvc) or for
* security constraints requiring CORS checks to be performed at {@link javax.servlet.Filter}
* level.
*
*
This filter could be used in conjunction with {@link DelegatingFilterProxy} in order
* to help with its initialization.
*
* @author Sebastien Deleuze
* @since 4.2
* @see CORS W3C recommendation
*/
public class CorsFilter extends OncePerRequestFilter {
private final CorsConfigurationSource configSource;
private CorsProcessor processor = new DefaultCorsProcessor();
/**
* Constructor accepting a {@link CorsConfigurationSource} used by the filter
* to find the {@link CorsConfiguration} to use for each incoming request.
* @see UrlBasedCorsConfigurationSource
*/
public CorsFilter(CorsConfigurationSource configSource) {
Assert.notNull(configSource, "CorsConfigurationSource must not be null");
this.configSource = configSource;
}
/**
* Configure a custom {@link CorsProcessor} to use to apply the matched
* {@link CorsConfiguration} for a request.
*
By default {@link DefaultCorsProcessor} is used.
*/
public void setCorsProcessor(CorsProcessor processor) {
Assert.notNull(processor, "CorsProcessor must not be null");
this.processor = processor;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
if (corsConfiguration != null) {
boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
if (!isValid || CorsUtils.isPreFlightRequest(request)) {
return;
}
}
}
filterChain.doFilter(request, response);
}
}
以上红色标记为拦截器用到配置文件的方法
发现在初始化实例的时候,
private final CorsConfigurationSource configSource;
该配置类为final类型,在刷新程序实例后,该数据还是不会发生改变
问题找到了,那么接下来我们把final去掉就可以了
一下为解决方案
重写CorsFilter 方法,自定义 MyCorsFilter 方法
注入自定义配置文件类
CorsConfiguration 配置从自定义配置类中读取
package com.smk.common.interceptor;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsProcessor;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.DefaultCorsProcessor;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.OncePerRequestFilter;
import com.smk.common.interceptor.bean.CorsConfigBean;
public class MyCorsFilter extends OncePerRequestFilter{
private CorsProcessor processor = new DefaultCorsProcessor();
@Autowired
private CorsConfigBean corsConfigBean;
private final CorsConfigurationSource configSource;
/**
* Constructor accepting a {@link CorsConfigurationSource} used by the filter
* to find the {@link CorsConfiguration} to use for each incoming request.
* @see UrlBasedCorsConfigurationSource
*/
public MyCorsFilter(CorsConfigurationSource configSource) {
Assert.notNull(configSource, "CorsConfigurationSource must not be null");
this.configSource = configSource;
}
/**
* Configure a custom {@link CorsProcessor} to use to apply the matched
* {@link CorsConfiguration} for a request.
* By default {@link DefaultCorsProcessor} is used.
*/
public void setCorsProcessor(CorsProcessor processor) {
Assert.notNull(processor, "CorsProcessor must not be null");
this.processor = processor;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration corsConfiguration = corsConfigBean.getCorsConfiguration();
//.getCorsConfiguration(request);
if (corsConfiguration != null) {
boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
if (!isValid || CorsUtils.isPreFlightRequest(request)) {
return;
}
}
}
filterChain.doFilter(request, response);
}
}
自定义配置文件类 初始化
CorsConfiguration 类
package com.smk.common.interceptor.bean;
import java.util.Arrays;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import com.smk.common.lang.RString;
import lombok.Data;
@RefreshScope
@Data
@Component
public class CorsConfigBean{
@Value("${AllowedOrigins}")
private String allowedOrigins;
private CorsConfiguration corsConfiguration;
@PostConstruct
public void init() {
this.corsConfiguration =buildConfig();
}
public CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
if(RString.isBlank(allowedOrigins)){
corsConfiguration.addAllowedOrigin("*");
}else{
corsConfiguration.setAllowedOrigins(Arrays.asList(allowedOrigins.split(",")));
}
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
}
启动时实例化
@Bean
public MyCorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
if(RString.isBlank(corsConfigBean.getAllowedOrigins())){
corsConfiguration.addAllowedOrigin("*");
}else{
corsConfiguration.setAllowedOrigins(Arrays.asList(corsConfigBean.getAllowedOrigins().split(",")));
}
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
return new MyCorsFilter(source);
}