09、Spring Security 实战 - 解决跨域问题和 Axios 所需配置
啥是跨域?
在小编的这篇博客中阐述了——【AJAX】AJAX的跨域问题,这编只说跨域的方案。
这里说明一下下面SpringMVC 跨域方案测试案例中前端的核心代码如下,就一个 Ajax 请求,然后将内容渲染出来:
首先是对 axios
的一些初始化:
然后向后端发送Ajax请求,将响应数据渲染,代码如下:
<script setup>
import {
ref } from 'vue'
import axios from '../utils/index.js'
const content = ref('')
axios.get(/test).then(res=>`{
content.value = res
}).catch(err=>{
console.log(err)
})
</script>
<template>
<div>{
{content}}</div>
</template>
如果没有跨域成功会有如下错误:
一、SpringMVC 跨域的解决方案
@CrossOrigin(注解的方式解决)
SpringMVC 中第一种处理跨域的方式是通过 @CrossOrigin 注解来标记支持跨域,该注解可以添加在方法上,也可以添加在类上——根据如下框住的元注解可知:
具体案例配置如下:
@RestController
public class TestController {
@CrossOrigin("http://localhost:5173")
@GetMapping("/test")
public String test(){
return "test";
}
}
@CrossOrigin 注解各属性含义如下:
- maxAge:预检请求的有效期,有效期内不必再次发送预检请求,默认是 -1.
- methods:允许的请求方法,*表示允许所有方法(请求方式).
- origins:允许的域,* 表示允许所有域,和 value 属性是一样的。
案例测试结果如下
addCorsMappings(实现WebMvcConfigurer接口,重写方法)
@CrossOrigin 注解需要添加在不同的 Controller 上。所以还有一种全局的配置方法,就是通过重写 WebMvcConfigurer#addCorsMappings 方法来实现,具体配置如下:
@Configuration
public class WebMvcOriginConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")// 对所有请求进行跨域
.allowedOriginPatterns("http://localhost:5173")
.maxAge(-1)
.allowedMethods("*");
}
}
TestController
@RestController
public class TestController {
// @CrossOrigin("http://localhost:5173")
@GetMapping("/test")
public String test(){
return "test";
}
}
测试结果
二、Spring Security 跨域的解决方案
当我们为项目添加了 Spring Security 依赖之后,上面俩种跨域方式会失效。 所以咱得会 Spring Security 为我们提供的跨域方案。
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.addFilterAfter(loginFilter(http),LogoutFilter.class)
.cors()
.configurationSource(this.corsConfigurationSource())
.and()
.csrf()
.disable()
.build();
}
private CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedHeader("*"); // 这个得加上,一些复杂的请求方式会带有header,不加上跨域会失效。
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addExposedHeader("*");
corsConfiguration.addAllowedOriginPattern("http://localhost:5173");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
注1:corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedHeader(" * “);
corsConfiguration.addExposedHeader(” * "); 这三都应该加上,原因1:一些请求方式发送的请求会带有请求头,不允许的话会被 CorsFilter
过滤器给过滤掉,即跨域失败;原因2:凭证信息不包含的话那认证过滤的时候会失败,从而导致请求失败。
注2:那配置的安全过滤器链的方法里,有配置自定义的 LoginFilter,那是用于处理 JSON 格式的登录认证,在小编Spring Security 实战 专栏中有专门的博客说明,这里不具体解释了。
前后端跨域测试(前端相关配置)
由于集成了 Spring Security,登录后需要进行认证,认证完请求服务器端要认证的资源需要携带其认证的Cookie(也就是那个SessionID,表明已经认证了)。那么在前端使用 Axios 发送跨域请求的时候,就需要配置 axios.defaults.withCredentials = true
。这是用于控制在发送跨域请求时是否携带身份凭证的(例如 Cookie、Http认证等),当然后端也需要配置。(当然不集成 Spring Security的话,是不需要配置这个的,因为什么登录认证是按你自己设定的程序走,不是由 Spring Security 去帮你管理了)
前端代码:
Axios 相关配置
测试代码
<script setup>
import {
ref } from 'vue'
import axios from '../utils/index.js'
const content = ref('')
const userInfo = {
"username" : "root",
"password" : "123"
}
let flag = false
function login() {
axios.post(/api/auth/login, userInfo).then(res =>` {
console.log(res)
content.value = JSON.stringify(res)
flag = true
}).catch(err=>{
console.log(666999)
console.log(err)
})
}
function test(){
axios.get(/test,{
withCredentials: true, //设置跨域的时候传递cookie,需要服务端的配合
}).then(res=>{
console.log(res)
content.value = res
}).catch(err=>{
console.log(666)
console.log(err)
})
}
</script>
<template>
<div>
<button @click="login">登录</button><br><br>
<button @click="test">发送测试请求</button><br><br>
<div>
<p>{
{content}}</p>
</div>
</div>
</template>
测试结果