Vue3 + Spring WebMVC 验证码案例中的跨域问题与解决方法

最近在基于vue3 + SpringWebMVC前后端分离的开发环境中实现一个验证码的案例,在开发过程中遇到了一些复杂的跨域问题,现已解决,故将解决方法分享,希望能帮到有需要的人。

出现的问题:

对于验证码的实现,我选择引入第三方Jar包,在开发至验证码校验时,此时正常逻辑为:前端向后端请求验证码图片,后端返回验证码图片并设置cookie,将正确验证码存储至session中;当用户提交验证码后,前端会发送ajax请求携带用户输入信息给后端,后端根据请求所携带的cookie从session中获取正确验证码与用户输入进行比对,然后返回校验结果。

在实际开发中,前端请求验证码图片时,后端返回了图片并设置了cookie,但在提交验证码时,请求未携带cookie,导致后端无法从session中获取正确的验证码。

问题原因分析:

我在进行代码排查时,发现校验请求所设置的session存在如下提示,即:set-cookie没有指定SameSite属性,默认为Lax。

SameSite是cookie中的一个属性,用于控制cookie在跨站请求时的发送策略,其属性值存在三个,如下:

**SameSite=Strict:**最为严格,cookie仅在相同站点进行发送

**SameSite=Lax:**相对宽松,在跨站顶级导航且请求方法为GET时也会发送cookie,但对于跨站请求(表单提交、ajax请求)则不会发送cookie

**SameSite=None:**最为宽松,允许cookie在跨站请求中发送,但是必须同时设置Secure属性为true,即只能通过Https协议传输

在此处,由于SameSite默认为Lax,浏览器会自动阻断cookie传输,这就导致了请求时未携带cookie

解决方案:

1,配置跨域访问

后端:可以在控制器上使用@CrossOrigin注解,也可以通过实现WebMvcConfigurer接口的addCorsMappings方法来全局配置跨域,我使用的是注解的方式。需要注意的是,注解中的allowCredentials属性必须设置为true,表示允许接收cookie

javascript 复制代码
@CrossOrigin(origins = "允许访问的域名", allowCredentials = "true")

前端:我使用的是axios模块发送ajax请求,设置如下:

javascript 复制代码
  // 全局配置,允许携带cookie
  axios.defaults.withCredentials = true
2,修改 SameSite属性

后端将cookie SameSite属性修改为None,使其允许跨域访问;而当我们将SameSite属性修改为None时,secure属性必须设置为true;这样做是为了允许cookie在跨域请求时发送,并确保cookie只能通过Https传输,增强安全性。

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

@Configuration
public class CookieConfig {

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        // 设置cookie名称
        serializer.setCookieName("JSESSIONID");
        // 设置cookie地址
        serializer.setCookiePath("/");
        // 设置 HttpOnly属性
        serializer.setUseHttpOnlyCookie(true);
        // 设置Secure属性(仅Https)
        serializer.setUseSecureCookie(true); 
        // 设置 SameSite属性为None
        serializer.setSameSite("None"); 
        return serializer;
    }
}
3,启用Https

secure属性为true,即仅允许https传输,故我们还需要将前后端服务网络协议更换为https。只需为前后端添加证书,启用https协议即可

后端:使用keytool工具生成自签名证书,将其放在并在src/main/resource目录下,并在application.yml中配置Https

java 复制代码
server:
  port: 8443
  ssl:
    key-store: classpath: 证书文件名称.p12
    key-store-password: 证书密码
    key-store-type: PKCS12
    key-alias: tomcat

前端:使用openssl生成自签名证书,并在vite.config.js中配置Https

javascript 复制代码
import { defineConfig } from 'vite'

export default defineConfig({
  server: {
    https: {
      key: "xxx/key.pem",
      cert: "xxx/cert.pem"
    }
  }
})

注意事项:

  • SameSite=None 和 Secure=true 必须同时使用
  • 在生产环境中建议使用正式的SSL证书,而不是自签名证书
  • 上述配置完毕后均需重启服务生效
相关推荐
Jeled2 天前
Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
android·okhttp·android studio·retrofit
Jeled3 天前
Android 网络层最佳实践:Retrofit + OkHttp 封装与实战
android·okhttp·kotlin·android studio·retrofit
allk555 天前
OkHttp源码解析(一)
android·okhttp
allk555 天前
OkHttp源码解析(二)
android·okhttp
aFakeProgramer5 天前
拆分PDF.html 办公小工具
okhttp
一壶浊酒..7 天前
ajax局部更新
前端·ajax·okhttp
洛克大航海10 天前
Ajax基本使用
java·javascript·ajax·okhttp
whltaoin16 天前
Java 网络请求 Jar 包选型指南:从基础到实战
java·http·okhttp·网络请求·retrofit
华农第一蒟蒻17 天前
谈谈跨域问题
java·后端·nginx·安全·okhttp·c5全栈
一直向钱19 天前
android 基于okhttp的socket封装
android·okhttp