springboot+vue2.x 解决session跨域失效问题
服务端SpringBoot2.x :localhost:8082
前端Vue2.x :localhost:81
前后端的端口号不同,为跨域,导致前端访问后端时,每次访问都新生产一个sessionID。解决如下:
后端:
1.添加过滤器:
package com.nsoft.gkzp.syscore.config.filter; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration //内置tomcat运行不加它没问题,但后来改为用外置tomcat时,启动后过滤器会失效,后来查明原因需要加上@Configuration才行
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
public class CorsFilter implements Filter { final private static Logger logger = LogManager.getLogger(CorsFilter.class);
@Override
public void destroy() {
}
/**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String origin = request.getHeader("Origin");
if(origin == null) {
origin = request.getHeader("Referer");
}
response.setHeader("Access-Control-Allow-Origin", origin);// 允许指定域访问跨域资源(这里不能写*,*代表接受所有域名访问,如写*则下面一行代码无效。谨记)
response.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许客户端携带cookie(此时origin值不能为“*”,只能为指定单一域名)
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); /// 允许浏览器在预检请求成功之后发送的实际请求方法名
response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin, X-Requested-With, Content-Type, Accept,Access-Token");// 允许浏览器发送的请求消息头
//response.setHeader("Access-Control-Max-Age", "86400"); // 浏览器缓存预检请求结果时间,单位:秒 chain.doFilter(request,response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
} }
2. springboot2.配置过滤器时,启动类必须加上@ServletComponentScan才会加载过滤器
package com.nsoft.gkzp; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /**
* springboot入口
* MapperScan("com.nsoft.gkzp.**.dao")为扫描mapper, 所以dao下面的类就不需要添加@mapper注解了
* ServletComponentScan 添加了过滤器,故这里要添加@ServletComponentScan注解,spring才会扫描到过滤器(eg:com.nsoft.gkzp.syscore.config.filter.CorsFilter)
*/
@SpringBootApplication
@ServletComponentScan
@MapperScan("com.nsoft.gkzp.**.dao")
public class GzyGkzpApplication { public static void main(String[] args) {
SpringApplication.run(GzyGkzpApplication.class, args);
} /**
* 在springboot整合vue前端时,vue使用url跳转时报404错误,此处代码解决此问题
* 参照https://blog.csdn.net/Mr_EvanChen/article/details/83625082
*/
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
return factory -> {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");
factory.addErrorPages(error404Page);
};
} }
3. spring-session 2.x 中 Cookie里面了SameSite ,他默认值是 Lax
SameSite Cookie 是用来防止CSRF攻击,它有两个值:Strict、Lax
SameSite = Strict:意为严格模式,表明这个cookie在任何情况下都不可能作为第三方cookie;
SameSite = Lax :意为宽松模式,在get请求是可以作为第三方cookie,但是不能携带cookie进行跨域post访问(这就很蛋疼了,我们那个校验接口就是POST请求)
package com.nsoft.gkzp.syscore.config; 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;
/**
* https://www.cnblogs.com/hujinshui/p/11025848.html
* spring-session 2.x 中 Cookie里面引入了SameSite他默认值是 Lax,
* SameSite Cookie 是用来防止CSRF攻击,它有两个值:Strict、Lax
* SameSite = Strict:意为严格模式,表明这个cookie在任何情况下都不可能作为第三方cookie;
* SameSite = Lax:意为宽松模式,在get请求是可以作为第三方cookie,但是不能携带cookie进行跨域post访问
* 总结:前端请求到后台,每次session都不一样,每次都是新的会话,导致获取不到用户信息
*/
@Configuration public class SpringSessionConfig {
public SpringSessionConfig() { }
@Bean
public CookieSerializer httpSessionIdResolver() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); // 取消仅限同一站点设置
cookieSerializer.setSameSite(null); return cookieSerializer;
}
}
前端:
1.在 main.js (前端用axios)
import axios from 'axios';
axios.defaults.withCredentials=true;//让ajax携带cookie
用了1天半时间,改了很多次依然不行,后来发现是前端用了 proxy 代理,它本身也是已经处理了跨域问题,网上找的时候发现有的文章也用到这个了。但我这里就是不行。
我原来的代码:
1)写的注册页面:

2)全局配置如下:
main.js
// xenv 标记当前环境 true:开发环境 false:生产环境
const xenv = true;
// 注册全局变量
Vue.prototype.$global = {
//contentPath 标记根路径,主要用于axios请求后端数据的url
contentPath: xenv ? '/api/' : router.options.base
};
(xenv设为true;所以 根路径contentPath的值必为‘/api/’ ,而‘/api/’ 在vue.config.js里配置为代理,如下。)
vue.config.js
devServer: {
open: true,
host: '0.0.0.0',
port: ,
https: false,
hotOnly: false,
before: app => {
},
proxy: {
// 配置跨域
'/api': {
target: 'http://127.0.0.1:8082/',
ws: true,
changOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
},
2.不使用proxy代理,把根目录写死为'http://127.0.0.1:8082/',就成功了,修改如下:
main.js:
// xenv 标记当前环境 true:开发环境 false:生产环境
const xenv = true;
// 注册全局变量
Vue.prototype.$global = {
// contentPath 标记根路径,主要用于axios请求后端数据的url
// contentPath: xenv ? '/api/' : router.options.base
contentPath: 'http://127.0.0.1:8082/'
};
4. 跨域白名单
(为了安全起见,可在服务端设置可跨域访问的白名单地址)
1. 自定义了一个配置文件 D:\workspace-gzy-gkzp\src\main\resources\resources\config.properties (这里对于localhost,127.0.0.1两个ip,不要放到正式环境。否则如对方用本地环境,去访问正式的后台,会被允许跨域访问,不安全)
#允许CORS的IP(即可跨域访问白名单,添加多个用英文逗号隔开coreFile.java)((端口号固定为application.properties配置的server.port))
system.accessControlAllowOrigin =192.168.1.61,zshj.com.cn
#测试环境加上localhost,127.0.0.1 system.accessControlAllowOrigin =localhost,127.0.0.1,,zshj.com.cn
2.读取配置文件类 D:\workspace-gzy-gkzp\src\main\java\com\nsoft\gkzp\syscore\config\MyDefinedUtil.java
package com.nsoft.gkzp.syscore.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource; /**
* 自定义配置类 获取config.properties相关参数
*( 其他类获取值,请用注解@Autowired 方式 ,否则获取不到值)
* @author zdyang
* @date 2019.08.30
*/
@Configuration //标识这个是一个配置类
@PropertySource(value = "classpath:resources/config.properties")
public class MyDefinedUtil {
@Value("${system.encoding:UTF-8}") //冒号后的值为没有配置文件时,制动装载的默认值 //下面的属性不能为static类型,否则获取不到值
public String SYSTEM_ENCODING; //#System Encoding //文件管理
@Value("${system.file.folder.img}")
public String SYSTEM_FILE_FOLDER_IMG; //允许跨域白名单
@Value("${system.accessControlAllowOrigin}")
public String SYSTEM_ACCESSCONTROLALLOWORIGIN;
}
3.跨域配置类:D:\workspace-gzy-gkzp\src\main\java\com\nsoft\gkzp\syscore\config\filter\CorsFilter.java
package com.nsoft.gkzp.syscore.config.filter; import com.nsoft.gkzp.syscore.config.MyDefinedUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration //内置tomcat运行不加它没问题,但后来改为用外置tomcat时,启动后过滤器会失效,后来查明原因需要加上@Configuration才行
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
public class CorsFilter implements Filter { final private static Logger logger = LogManager.getLogger(CorsFilter.class); @Autowired
MyDefinedUtil myDefinedUtil; @Override
public void destroy() {
} /**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String origin = request.getHeader("Origin");
if(origin == null) {
origin = request.getHeader("Referer");
} //允许跨域白名单
String whiteList=myDefinedUtil.SYSTEM_ACCESSCONTROLALLOWORIGIN;
boolean isValid = false;
String adressIP = null;//截取地址栏的ip地址
if(origin != null){
try {
adressIP = origin.substring(origin.indexOf("://") + 3);
int b = adressIP.indexOf(":");//有端口号情况 eg:https://127.0.0.1:8080
if (b > 0) {
adressIP = adressIP.substring(0, b);
}else{
b = adressIP.indexOf("/");//如果是默认端口号,地址栏不填写端口情况(443 80)eg: https://127.0.0.1
if (b > 0) {
adressIP = adressIP.substring(0, b);
}
}
isValid = whiteList.contains(adressIP); //将origin截出ip字符串
}catch (Exception e){
logger.error("白名单校验出错:"+e.getMessage(),e);
}
}
logger.info("跨域验证:origin="+origin+"***adressIP="+adressIP+"***isValid="+isValid);// 如为跨域请求,下面的"Access-Control-Allow-Origin"值置为null,就无法访问了。。。如果为非跨域请求,这个为null不会受影响,依然允许访问
response.setHeader("Access-Control-Allow-Origin", isValid ? origin : "null");// 允许指定域访问跨域资源(这里不能写*,*代表接受所有域名访问,如写*则下面一行代码无效。谨记)
response.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许客户端携带cookie(此时origin值不能为“*”,只能为指定单一域名)
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); /// 允许浏览器在预检请求成功之后发送的实际请求方法名
response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin, X-Requested-With, Content-Type, Accept,Access-Token");// 允许浏览器发送的请求消息头
//response.setHeader("Access-Control-Max-Age", "86400"); // 浏览器缓存预检请求结果时间,单位:秒
//logger.info("****************测试过滤器及日志1111");
chain.doFilter(request,response);
//logger.error("****************测试过滤器及日志2222");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
} }
白名单心路历程如下:
首先参考 https://blog.csdn.net/qq_15054679/article/details/90684703 :
config.properties
#允许CORS的IP(即可跨域访问白名单,添加多个用英文逗号隔开)(本地连接在CorsFilter.java中已设置,就不在这里配置了)
system.accessControlAllowOrigin =http://localhost:
CorsFilter.java
package com.nsoft.gkzp.syscore.config.filter; import com.nsoft.gkzp.syscore.config.MyDefinedUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration //内置tomcat运行不加它没问题,但后来改为用外置tomcat时,启动后过滤器会失效,后来查明原因需要加上@Configuration才行
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
public class CorsFilter implements Filter { final private static Logger logger = LogManager.getLogger(CorsFilter.class); @Autowired
MyDefinedUtil myDefinedUtil; @Override
public void destroy() {
}
/**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String origin = request.getHeader("Origin");
if(origin == null) {
origin = request.getHeader("Referer");
}
//允许跨域白名单
String[] whiteList = (myDefinedUtil.SYSTEM_ACCESSCONTROLALLOWORIGIN).split(",") ;
boolean isValid = false;
logger.info("origin="+origin);
for(String ip : whiteList){
if(origin != null && origin.equals(ip)){
isValid = true;
break;
}
}
logger.info("isValid="+isValid);//如为跨域请求,下面的"Access-Control-Allow-Origin"值置为null,就无法访问了。。。如果为非跨域请求,这个为null不会受影响,依然允许访问
response.setHeader("Access-Control-Allow-Origin", isValid ? origin : "null");// 允许指定域访问跨域资源(这里不能写*,*代表接受所有域名访问,如写*则下面一行代码无效。谨记)
response.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许客户端携带cookie(此时origin值不能为“*”,只能为指定单一域名)
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); /// 允许浏览器在预检请求成功之后发送的实际请求方法名
response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin, X-Requested-With, Content-Type, Accept,Access-Token");// 允许浏览器发送的请求消息头
//response.setHeader("Access-Control-Max-Age", "86400"); // 浏览器缓存预检请求结果时间,单位:秒
chain.doFilter(request,response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
上面代码用 origin.equals(ip) 去判定不是很好。
原因是测试时发现,
1)origin如果是域名的话(值为http://zhxy.nsoft.com.cn:8082),如果是ip地址的话会有斜杠(值为:http://120.24.253.6:8082/)。这样在config.properties配置文件配置白名单参数system.accessControlAllowOrigin时会有很多,其很麻烦
2)我把http协议改为https协议时:端口号变了,http也改成https,参数system.accessControlAllowOrigin改的时候也很麻烦。
参照:
https://www.cnblogs.com/zimublog/p/10786110.html
https://blog.csdn.net/qq_17555933/article/details/92017890
springboot+vue2.x 解决session跨域失效问题的更多相关文章
- 解决AJAX session跨域失效
1.想实现的功能是登录时有个验证码,这个验证码后台提供,然后放在session中,前台把用户输入的验证码通过AJAX发给后台,后台把session中的验证码取出来然后比较不同,一样则通过. 问题出现在 ...
- 【分布式系列】session跨域及单点登录解决方案
Cookie机制 Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息. ...
- thinkphp中session跨域问题
问题描述 <thinkphp实现短信验证注册>中,小编不止记录了短信验证码的实现方法,同时还记录了图片验证码的实现方法. 本地使用,一切正常:后端项目和前端项目都部署到服务器,一切正常:后 ...
- 170222、使用Spring Session和Redis解决分布式Session跨域共享问题
使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...
- 使用Spring Session和Redis解决分布式Session跨域共享问题
http://blog.csdn.net/xlgen157387/article/details/57406162 使用Spring Session和Redis解决分布式Session跨域共享问题
- 解决windows下Chrome78以上跨域失效问题
1. 为什么需要解决chrome浏览器跨域的问题? 基于Hybird App的H5部分,可以直接打包进apk或者ipa包中,在开发过程中也不需要放置到临时搭建的服务器上,直接在本地打开html静态页面 ...
- sso单点登录的入门(Session跨域、Spring-Session共享)
1.单点登录,就是多系统,单一位置登录,实现多系统同时登录的一种技术.单点登录一般是用于互相授信的系统,实现单一位置登录,全系统有效的. 区分与三方登录(第三方登录) ,三方登录:某系统,使用其他系统 ...
- java:sso(单点登录(single sign on),jsp文件动静态导入方式,session跨域)
1.jsp文件导入: 2.session跨域: 3.sso(单点登录(single sign on): sso Maven Webapp: LoginController.java: package ...
- (十)整合 JWT 框架,解决Token跨域验证问题
整合 JWT 框架,解决Token跨域验证问题 1.传统Session认证 1.1 认证过程 1.2 存在问题 2.JWT简介 2.1 认证流程 2.2 JWT结构说明 2.3 JWT使用方式 3.S ...
随机推荐
- 百度网盘快速下载工具下载:Pandownload下载
众所周知的百度网盘下载限速很厉害,所以就有了快速下载工具出现了.一般情况下,按照家里网速有多快,使用工具下载就有多快. 可以直接复制如下图进行下载: 另外,PanDownload[百度网盘下载工具]无 ...
- Spring+SpringMVC+Spring Data JPA完美整合
使用Maven实现SSS框架的整合. 方便记录,专门建了一个pom项目用来整合SSS框架所用的jar包 1.POM项目,作为父级项目,记录整个整合中的依赖jar包pom文件 <project x ...
- 升级到11.2.0.4后用srvctl无法启用数据库实例,报CRS-0254: authorization failure
在standby database上从11.2.0.3升级11.2.0.4,然后打了补丁PATCH SET UPDATE 11.2.0.4.190115后,无法用srvctl启动第二个节点数据库实例: ...
- C++文件fstream的操作
用到的关于输入输出fstream流相关的知识 1.两个主要函数:read( )函数 从流中读取字符串的成员函数read 该成员函数一般形式是:read(char* pch, int nCount) 从 ...
- 解决SQL语句在Dapper执行超时比Query慢的问题
在语句结尾加上 Add OPTION (RECOMPILE) to the end https://stackoverflow.com/questions/10933366/sp-executesql ...
- MySQL单机优化---分表、分区、分库
一.分表: 水平分表:根据条件把数据分为N个表(例如:商品表中有月份列,则可以按月份进行水平分表). 使用场景:一张表中数据太多,查询效率太慢. 当需要同时查询被水平分表的多张表时: 在两条SQL语句 ...
- springboot异步线程
前言 最近项目中出现了一个问题,发现自己的定时器任务在线上没有执行,但是在线下测试时却能执行,最后谷歌到了这篇文章SpringBoot踩坑日记-定时任务不定时了?; 本篇文章主要以自己在项目中遇到的问 ...
- 题解 CF53E 【Dead Ends】
题意: 给一个n(n<=10)个节点的无向图,图里面有m条边,以这m条边构建生成树,求所有生成树中只含有k个度数为1的点的方案数. 题解: 看见这个数量级就一定会想到状态压缩dp... 那让我们 ...
- 利用MySQL存储过程批量插入100W条测试数据
DROP PROCEDURE IF EXISTS insert_batch; CREATE PROCEDURE insert_batch() BEGIN ; loopname:LOOP '); ; T ...
- day25——私有成员、类方法、静态方法、属性、isinstance和issubclass的区别
day25 类的私有成员 当你遇到重要的数据,功能(只允许本类使用的一些方法,数据)设置成私有成员 python所有的私有成员都是纸老虎,形同虚设 类从加载时,只要遇到类中的私有成员,都会在私有成员前 ...