引言
该项目主要使用技术:sprinboot、springSecurity、vue,其它的技术就不介绍了
其中springSecurity是我参考网上的案例去进行的集成,虽然集成成功了,但是还不是太懂。
下面就开始介绍一下我遇到的问题
问题重现
由于我项目后端集成了springSecurity,所以项目的登录验证和鉴权就是使用的springSecury来进行的,前端的话使用的element-ui-admin作为模板进行二开。
起初前端在进行登录的时候是可以正常访问后端不会出现跨域的问题,直到到了后面请求我的一个delete
接口,这个时候就出现了跨域
的问题,通过f12
可以看见报403错误以及options错误
尝试修改Configuration(×)
然后我就去调我后端之前配置的跨域配置,如下是我原来的配置:
/**
* <p>
* 解决跨域问题
* </p>
*
* @author:雷子杰
* @date:2022/10/29
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")//允许任何方法
.allowCredentials(true)
.maxAge(3600);
}
}
其实我这个配置是没问题的,所以改来改去还是没啥作用。
尝试增加@CrossOrigin(×)
然后我就想到在Controller
层增加@CrossOrigin
,但是加了后还是没啥用
尝试更改前端跨域(×)
前端跨域就是webpack
来进行请求代理,在vue.config.js
中去添加以下即可,但是我添加了后,似乎是没了跨域的问题,但出现了新的问题,前端传过去的request
中的数据是null(无法获取登录时用户传过去的数据,但前端确实是传过去了的)
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
},
before: require('./mock/mock-server.js'),
proxy: {
'/api': {
// 代理名称 凡是使用/api开头的地址都是用此代理
target: 'http://192.168.1.6:8888', // 需要代理访问的api地址
changeOrigin: true, // 允许跨域请求
secure: false, // 忽略 HTTPS 安全提示
pathRewrite: {
// 重写路径,替换请求地址中的指定路径
'^/api': '' // 将请求地址中的/api替换为空,也就是请求地址中不会包含/api/
}
}
},
disableHostCheck: true
}
问题原因
产生问题的原因在标题就已经说明了,就是跨域的问题,但是产生的原因的话,不太清楚,我后面看了下我之前下载的编程不良人springSecurity
的笔记,发现他在笔记中写道如下:
后端跨域问题的解决的三种解决方案
-
@CrossOrigin
Spring 中第一种处理跨域的方式是通过@CrossOrigin 注解来标记支持跨域,该注解可以添加在方法上,也可以添加在 Controller 上。当添加在 Controller 上时,表示 Controller 中的所有接口都支持跨域
@RestController public Class HelloController{ @CrossOrigin (origins ="http://localhost:8081") @PostMapping ("/post") public String post (){ return "hello post"; } }
-
addCrosMapping
@CrossOrigin 注解需要添加在不同的 Controller 上。所以还有一种全局配置方法,就是通过重写 WebMvcConfigurerComposite#addCorsMappings方法来实现,具体配置如下:
@Configuration public class WebMvcConfig implements WebMvcConfigurer{ Override public void addCorsMappings (CorsRegistry registry){ registry.addMapping("/**") //处理的请求地址 .allowedMethods ("*") •allowedorigins("*") .allowedHeaders ("*") .allowCredentials (false) •exposedHeaders ("") .maxAge (3600) ; } }
-
CrosFilter
Cosr Filter 是Spring Web 中提供的一个处理跨域的过滤器,开发者也可以通过该过该过滤器处理跨域。
@Configuration public class WebMvcConfig { @Bean FilterRegistrationBean<CorsFilter> corsFilter() { FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedHeaders(Arrays.asList("*")); corsConfiguration.setAllowedMethods(Arrays.asList("*")); corsConfiguration.setAllowedOrigins(Arrays.asList("*")); corsConfiguration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfiguration); registrationBean.setFilter(new CorsFilter(source)); registrationBean.setOrder(-1);//filter 0 1 return registrationBean; } }
SprngSecurity跨域原理分析
当我们为项目添加了 Spring Security 依赖之后,发现上面三种跨域方式有的失效了,有
则可以继续使用,这是怎么回事?
通过@CrossOrigin 注解或者重写 addCorsMappings 方法配置跨域,统统失效了,通
CorsFilter 配置的跨域,有没有失效则要看过滤器的优先级,如果过滤器优先级高于 Sp
Security 过滤器,即先于 Spring Security 过滤器执行,则 CorsFiter 所配置的跨域处理依然有效;如果过滤器优先级低于 Spring Security 过滤器,则 CorsFilter 所配置的跨域处理就会失效。
为了理清楚这个问题,我们先简略了解一下 Filter、DispatchserServlet 以及Interceptor 执行顺序。
理清楚了执行顺序,我们再来看跨域请求过程。由于非简单请求都要首先发送一个预检请求
request),而预检请求并不会携带认证信息,所以预检请求就有被 Spring Security 拦截的可能。因此通过@CrossOrigin 注解或者重写 addCorsMappings 方法配置跨域就会失效。如果使用 CorsFilter 配置的跨域,只要过滤器优先级高于 SpringSecurity 过滤器就不会有问题。反之同样会出现问题。
解决方案
Spring Security 中也提供了更专业的方式来解决预检请求所面临的问题。如:
关键位置:configurationSource()
和.cors().configurationSource(configurationSource())
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest()
.authenticated()
.and()
.formLogin()
.and()
.cors() //跨域处理方案
.configurationSource(configurationSource())
.and()
.csrf().disable();
}
//这个是配置跨域方法
CorsConfigurationSource configurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
最终我解决的方式就是去掉我之前配置的addCrosMapping
,在springSecurity的配置文件中去进行跨域配置操作
总结
在学习的路上总是会遇到许多问题,一时无法解决不要紧,只要找准了方向,就一定能够解决!