服务端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跨域失效问题的更多相关文章

  1. 解决AJAX session跨域失效

    1.想实现的功能是登录时有个验证码,这个验证码后台提供,然后放在session中,前台把用户输入的验证码通过AJAX发给后台,后台把session中的验证码取出来然后比较不同,一样则通过. 问题出现在 ...

  2. 【分布式系列】session跨域及单点登录解决方案

    Cookie机制 Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息. ...

  3. thinkphp中session跨域问题

    问题描述 <thinkphp实现短信验证注册>中,小编不止记录了短信验证码的实现方法,同时还记录了图片验证码的实现方法. 本地使用,一切正常:后端项目和前端项目都部署到服务器,一切正常:后 ...

  4. 170222、使用Spring Session和Redis解决分布式Session跨域共享问题

    使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...

  5. 使用Spring Session和Redis解决分布式Session跨域共享问题

    http://blog.csdn.net/xlgen157387/article/details/57406162 使用Spring Session和Redis解决分布式Session跨域共享问题

  6. 解决windows下Chrome78以上跨域失效问题

    1. 为什么需要解决chrome浏览器跨域的问题? 基于Hybird App的H5部分,可以直接打包进apk或者ipa包中,在开发过程中也不需要放置到临时搭建的服务器上,直接在本地打开html静态页面 ...

  7. sso单点登录的入门(Session跨域、Spring-Session共享)

    1.单点登录,就是多系统,单一位置登录,实现多系统同时登录的一种技术.单点登录一般是用于互相授信的系统,实现单一位置登录,全系统有效的. 区分与三方登录(第三方登录) ,三方登录:某系统,使用其他系统 ...

  8. java:sso(单点登录(single sign on),jsp文件动静态导入方式,session跨域)

    1.jsp文件导入: 2.session跨域: 3.sso(单点登录(single sign on): sso Maven Webapp: LoginController.java: package ...

  9. (十)整合 JWT 框架,解决Token跨域验证问题

    整合 JWT 框架,解决Token跨域验证问题 1.传统Session认证 1.1 认证过程 1.2 存在问题 2.JWT简介 2.1 认证流程 2.2 JWT结构说明 2.3 JWT使用方式 3.S ...

随机推荐

  1. SpringBoot Error creating bean with name 'dataSource' defined in class path resource。。。

    启动spring boot项目出错 解决方法在Application类上增加:@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration ...

  2. netstat -lunpt未找到命令

    [root@localhost ~]# netstat -lunpt -bash: netstat: 未找到命令 [root@localhost ~]# yum -y install net-tool ...

  3. Operation之结合操作符

    startWith 该方法会在Observable序列开始之前插入一些事件元素. 即发生事件消息之前, 会发出这些预先插入的事件消息 Observable.of("2", &quo ...

  4. 【bat批处理】批量执行某个文件夹下的所有sql文件bat批处理

    遍历文件夹下所有的sql文件,然后命令行执行 for /r "D:\yonyou\UBFV60\U9.VOB.Product.Other" %%a in (*.sql) do ( ...

  5. Javascript / Nodejs call 和 apply

    call: 改变了函数运行的作用域,即改变函数里面this的指向apply:同call,apply第二个参数是数组结构 例如: this.name = 'Ab'var obj = {name: 'BB ...

  6. Git 初始仓库

    配置好环境后,通常有两种方式使用git,一种从git仓库上克隆,进行操作,一种是在本地创建并初始仓库,进行操作.工作中前者比较多见. 下面演示如何在本地创建仓库. 1.新建一个目录 # mkdir t ...

  7. POJ-图论-并查集模板

    POJ-图论-并查集模板 1.init:把每一个元素初始化为一个集合,初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变). void init() { for ...

  8. electron+vue实现菜单栏

    公司开发的产品都是用c++写的,而且还都是几个人,老板想搞下创新,就是看看能否通过其它的方式来实现前后端分离.然后我就了解到了electron这个东西,之前学安卓的时候看到过flutter,不经意间看 ...

  9. adb 常用命令汇总

    adb 常用命令: adb –help 查看帮助手册 adb devices 检测连接到电脑的安卓设备或安卓模拟器设备 adb pull  <手机路径>  <本机路径>  从手 ...

  10. 编程语言与python介绍

    目录 一.编程语言的发展史 1.1 机器语言 1.2 汇编语言 1.3 高级语言 1.3.1 编译型 1.3.2 解释型 1.4 总结 2.python介绍 2.1 python解释器版 2.2 运行 ...