SpringBoot自定义跨域信息并持久化存储实时刷新

本文详细介绍了如何在SpringBoot中自定义跨域策略,通过CorsFilter进行配置,并实现跨域信息的数据库持久化和实时刷新。重点讲解了CorsFilter的工作原理,避免常见问题及如何绕过final类型限制以实现动态刷新。
摘要由CSDN通过智能技术生成

SpringBoot自定义跨域信息并持久化存储实时刷新

本文介绍如何自定义跨域信息,如何实时刷新系统中的跨域配置,再结合数据库完成对跨域信息的存储,基本实现跨域信息通过API修改并同步刷新。

CorsFilter介绍与分析

首先看一下CorsFilter的继承结构
在这里插入图片描述CorsFilter是自Spring MVC 4.2后专用来处理CORS问题的Filter,通常情况下,我们只需要注入CorsFilter bean即可完成对跨域信息的配置。

@Bean
public CorsFilter corsFilter() {
    List<String> origins = new ArrayList<>();
    origins.add("http://auth-server.com:8888");
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    //允许所有请求来源
    corsConfiguration.setAllowedOrigins(origins);
    //放行哪些原始域(头部信息)
    corsConfiguration.addAllowedHeader("*");
    //设置放过校验的header
    corsConfiguration.addExposedHeader("Authorization");
    //哪些类型的请求可以通过
    corsConfiguration.addAllowedMethod("*");
    //为true时会发送cookies
    corsConfiguration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**",corsConfiguration);
    return new CorsFilter(source);
}

通过上述代码,注入了相应的跨域信息,包含允许哪些源地址、允许哪些Header等,通常我们为了开发方便,最容易出现的一个问题就是将AllowCredentials设置为true后,再将AllowedOrigins设置为*,当出现这种设置时,我们通常会遇见下面的错误信息:

java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value “*” since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider using “allowedOriginPatterns” instead.

简言之,当allowCredentials 设置为true时,allowedOrigins 不能出现特殊值 * 。所以建议还是不要偷懒,一个是这样本就是不建议的,另一方面,这对我们的应用来讲也并不安全。

如何实现跨域信息刷新

说到这里,首先说一下为什么需要实现跨域信息刷新。我们通常在完成跨域配置后(通过配置文件或其他方式),通常都需要重启应用来完成跨域信息的刷新,开发与线上都不是特别方便,如果跨域配置比较繁琐,更是加大了配置成本。如果可以通过可视化的操作,完成对跨域信息的整合,必将有效缩减开发成本。

通过对CorsFilter源码的分析,跨域信息初始化载入 CorsConfigurationSource中,而CorsFilter中将其定义为final类型,这将是阻止我们完成跨域刷新的一大障碍。
CorsFilter跨域配置类型定义为final
Spring通过相关注解注入的Bean在全局范围内都是单例的,那么我们只需要将环境中的CorsFilter的内容替换掉,我们的配置信息自然就生效了。要想修改之,首先去除定义的final类型,我们自定义一个跨域Filter:

public class ResourcesCorsFilter extends CorsFilter {

    private CorsProcessor processor = new DefaultCorsProcessor();

    private CorsConfigurationSource configSource;

    public ResourcesCorsFilter(CorsConfigurationSource configSource) {
        super(configSource);
        this.configSource = configSource;
    }

    @Override
    public void setCorsProcessor(CorsProcessor processor) {
        Assert.notNull(processor, "CorsProcessor must not be null");
        this.processor = processor;
    }

    public CorsConfigurationSource getConfigSource() {
        return this.configSource;
    }

    public void setConfigSource(CorsConfigurationSource configSource) {
        this.configSource = configSource;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
        boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
        if (isValid && !CorsUtils.isPreFlightRequest(request)) {
            filterChain.doFilter(request, response);
        }
    }
}

通过继承系统中的CorsFilter,最终将我们定义好的ResourcesCorsFilter 注入到安全认证的框架中去即可,我这边是用的是spring-security-oauth2-authorization-server:0.2.1,这里贴出部分资源服务关于跨域配置的代码:
安全框架终端自定义跨域配置载入
之后我们再通过@Bean注解,完成跨域信息的载入,后续需要修改跨域信息时,是需要调用自定义方法中的setConfigSource来实现对跨域信息的修改,这里我贴出部分修改的逻辑

@Override
public void freshCors(ResourcesCorsDto resourcesCorsDto) {
    //取出数据库中的相关存储信息
    String corsConfigStr = resourcesDictionaryService.loadKey(ResourcesDictionaryEnum.CORS_CONFIG);
    UrlBasedCorsConfigurationSource source = JSONObject.parseObject(corsConfigStr, UrlBasedCorsConfigurationSource.class);
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowedOrigins(resourcesCorsDto.getOrigins());
    corsConfiguration.setAllowCredentials(resourcesCorsDto.getAllowCredentials());
    corsConfiguration.setAllowedHeaders(resourcesCorsDto.getAllowHeaders());
    corsConfiguration.setExposedHeaders(resourcesCorsDto.getExposedHeaders());
    corsConfiguration.setAllowedMethods(resourcesCorsDto.getAllowedMethods());
    source.registerCorsConfiguration(resourcesCorsDto.getPattern(), corsConfiguration);
    //首先保证数据库存储
    resourcesDictionaryService.setKey(ResourcesDictionaryEnum.CORS_CONFIG, JSONObject.toJSONString(source));
    //加载程序中的跨域配置
    resourcesCorsFilter.setConfigSource(source);
}

至于结合数据库存储,这个只需要在修改跨域配置时,保证跨域信息成功的存储入数据库中,并能够修改环境中的配置即可。上面只是针对跨域配置的一点案例说明,欢迎各位斧正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dp_shiyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值