Spring Security 跨域配置
新建的 H5 页面项目在测试站出现跨域报错。但访问正式站的时候,竟然没有报错。H5 页面与后台的前端(前后端分离)请求的是同一个后端接口地址,只不过是在用户授权登录上使用了独立的验证(抄了若依的前后端分离版本的登录验证和 redisService 存储的 token 服务)。相当于是在现有项目上开了一个小口,允许不通过当前的 userDetailSerice 认证,直接访问。
以下是继承了 ResourceServerConfigurerAdapter
的 OAuthResourceConfig
配置:
@Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/xx/login/**", "/xx/h5/**").permitAll()
.antMatchers("/xx/**").authenticated();
}
一开始没读懂这些配置的内容,但 .antMatchers("/xx/login/**", "/xx/h5/**").permitAll()
放行请求是没问题的。主要是对 authorizeRequests()
理解有偏差,以为针对认证过的请求,放行 OPTIONS
类型的请求。
后面百度补了一些基础,authorizeRequests()
是在定义请求的授权规则之前,需要加上来返回可操作的对象。基本涉及到 路由 pattern 设置的都会加上这一句。authenticated()
才是要求请求已登录,存在验证过的授权,比如请求携带了有效的 token,并且验证通过了。
上面的配置允许 OPTIONS 请求通过,但显然这并不够,还需要设置返回的头部,允许访问的源 Origin 之类的,参考网上的补全:
@Override
public void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(configurationSource()).and().exceptionHandling()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/xx/login/**", "/xx/h5/**").permitAll()
.antMatchers("/xx/**").authenticated();
}
CorsConfigurationSource configurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
// corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
一开始设置的 Origins 为具体的测试站和正式站的源,但这显然不够灵活,应该是将访问的源设置为允许的源。但苦于不知道怎么加 request 进来获取,所以尝试设置为 *
,看是否可用。通过 Postman 设置 Headers 中 Origin 字段来调试,查看返回 Headers 中是否携带了 Access-Control-Allow-*
之类的字段,以此判断服务端是否允许跨域访问。如果携带了就说明服务端开启了允许跨域访问。测试发现,设置为 *
,返回的 Access-Control-Allow-Origin
刚好就是请求中设置的 Origin,也就是说这么设置正好实现了想要的效果。
反向代理解决跨域问题
之后反应过来,后台是前端分离的,后台的前端也应该存在相同的问题才是。然后就发现,原来前端做了反向代理。
这也是一种解决方案:
http://h5.xx.com/api/xx
-> http://xxx.com:8080/api/xx
通过宝塔面板,设置网站的反向代理 /api/
-> http://xxx.com:8080
,前端也修改一下访问地址为 /api/
然后就好了。