前后端分离跨域问题、session问题

1. 问题描述

SpringSecurity+Vue前后端分离使用验证码,后端将生成的验证码存入到session中,但是在进行验证码验证时获取session中的验证码值时null的,后端生成的验证码确实是生成好了。问题就是存不进session中。

2. 解决问题:以下三种方式
  1. 后端设置跨域:后端跨域问题有很多解决方式,这里只写一种通过配置类的方式。
  • 主要跨域类

/**
 * 解决跨域请求的
 */
@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //  你需要跨域的地址  注意这里的 127.0.0.1 != localhost
        // * 表示对所有的地址都可以访问
        // corsConfiguration.addAllowedOrigin("http://127.0.0.1");
        corsConfiguration.addAllowedOrigin("http://localhost");// 填自己的域名
        //  跨域的请求头
        corsConfiguration.addAllowedHeader("*"); // 2
        //  跨域的请求方法
        corsConfiguration.addAllowedMethod("*"); // 3

        //加上了这一句,大致意思是可以携带 cookie
        //最终的结果是可以 在跨域请求的时候获取同一个 session
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //配置 可以访问的地址
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }
}

实在不行的可以把跨域的方法全部加入跨域类、即如下


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 解决跨域请求的
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {
	// 方式一、返回CorsConfiguration 对象
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //  你需要跨域的地址  注意这里的 127.0.0.1 != localhost
        // * 表示对所有的地址都可以访问
        // corsConfiguration.addAllowedOrigin("http://127.0.0.1:8080");
        // corsConfiguration.addAllowedOrigin("http://localhost:8090/");
        // corsConfiguration.addAllowedOrigin("http://yuechi.com");
        corsConfiguration.addAllowedOrigin("*");
        //  跨域的请求头
        corsConfiguration.addAllowedHeader("*"); // 2
        //  跨域的请求方法
        corsConfiguration.addAllowedMethod("*"); // 3

        //加上了这一句,大致意思是可以携带 cookie
        //最终的结果是可以 在跨域请求的时候获取同一个 session
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

	// 方式二、加入bean
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //配置 可以访问的地址
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }

	
	/* 方式三、覆盖 WebMvcConfigurer 里的*/
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }

}

注意:在设置了allowCredentials(true)之后,allowedOrigins()就不能再设置为allowedOrigins("*"),而是把 * 替换成自己的域名,因为*不允许携带认证头和cookies,如果是*的话,浏览器将不会发送cookies,即使你的XHR设置了withCredentials。如果项目不需要session那么可以直接设置为 * 。这里我之前就是设置成*而我项目有需要session存放生成的验证码,所以经过自己设置的验证码过滤器时在session中没有拿到对应值(session是空的)。

相关原理如果要发送CookieAccess-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的也无法读取服务器域名下的Cookie。
删除线格式

参考链接:

  1. 前端设置跨域:
  • 通过新建vue.config.js文件添加,文件内容如下
module.exports = {
    // 部署生产环境和开发环境下的URL:可对当前环境进行区分,baseUrl 从 Vue CLI 3.3 起已弃用,要使用publicPath
    // baseUrl: process.env.NODE_ENV === 'production' ? './' : '/' 
    publicPath: process.env.NODE_ENV === 'production' ? '/public/' : './',
    // 输出文件目录:在npm run build时,生成文件的目录名称 
    outputDir: 'dist',
    // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录 
    assetsDir: "assets",
    // 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度 
    productionSourceMap: false,
    // 默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存,你可以通过将这个选项设为 false 来关闭文件名哈希。(false的时候就是让原来的文件名不改变)
    filenameHashing: false,
    // 代码保存时进行eslint检测
    lintOnSave: false,
    // webpack-dev-server 相关配置
    devServer: {
        // 自动打开浏览器
        open: true,
        host: 'localhost',
        // 端口
        port: 8090,
        // https
        https: false,
        // 热更新
        hotOnly: false,
        // 使用代理
        proxy: {
            '/api': {
                // 目标代理服务器地址
                target: 'http://localhost/',
                // 开启代理,本地创建一个虚拟服务器 允许跨域
                changeOrigin: true, 
            },
        },
    },
}
  • 通过axios添加前缀,在main.js中添加以下代码(前端常用方式,但是我出现的这个问题单单加这个解决不了)
// axios前缀,写了前缀发送axios请求时就可以不用在写前缀了,直接写接口地址
axios.defaults.baseURL = "http://localhost:8090/";
  • 通过在main.js添加axios.defaults.withCredentials = true;的方式,让当前请求为跨域类型时是在请求中协带cookie(也就是上面黄字的原理)。
// axios前缀也要加,
axios.defaults.baseURL = "http://localhost:8090/";
axios.defaults.withCredentials = true;

通过xhr设置,在axios请求头中添加。
相关原理withCredentials:表示XHR是否接收cookies和发送cookies,也就是说如果该值是false,响应头的Set-Cookie,浏览器也不会理,并且即使有目标站点的cookies,浏览器也不会发送。因为在默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。

虽然设置了widthCredentials为true的请求中会包含远程域的所有cookie,但这些cookie仍然遵循同源策略,所以外域是访问不了这些cookie的,现在我们就可以安全地跨域访问啦。

需要注意是,当配置了xhr.withCredentials = true时,必须在后端增加 response 头信息Access-Control-Allow-Origin,且必须指定域名,而不能指定为*。

如果在同域下配置xhr.withCredentials,无论配置true还是false,效果都会相同,且会一直提供凭据信息(cookie、HTTP认证及客户端SSL证明等)

  • 通过cors插件,在main.js中添加。
const  cors = require('koa2-cors');
app.use(cors({
  origin: "http://localhost:8090",// 即http://域名:端口
  credentials: true,
}));

3. 总结
  1. 前后端分离的项目,后端设置跨域的方式有多种,前端的解决方式也有几种
  2. 需要特别注意如果要发送CookieAccess-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名当配置了xhr.withCredentials = true时,必须在后端增加 response 头信息Access-Control-Allow-Origin,且必须指定域名,而不能指定为*
  3. 需要发送Cookie时就需要注意前后端跨域的匹配设置
  4. 如果还是不能解决,就前后端各种搭配设置分离,肯定有一种可以
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐