您现在的位置是:首页 >技术教程 >【深入浅出 Spring Security(九)】解决跨域问题和 Axios 所需配置网站首页技术教程

【深入浅出 Spring Security(九)】解决跨域问题和 Axios 所需配置

假正经的小柴 2024-10-12 12:01:04
简介【深入浅出 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>


测试结果

请添加图片描述

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。