springboot集成shiro+前端vue,前后端分离项目遇到跨域以及sessionid拿不到等问题

近期在写前后端分离的项目,由于前后端分离导致原来使用的shiro配置无法满足现有系统要求。同时在前后端分离项目中存在的一些问题。例如,一些用户信息需要存储在后端方便进行安全性判断,但这些存储在后端的session前端却获取不到(特别奇怪),以及浏览器访问后端接口出现的跨域问题。

1、跨域问题

由于前后端分离导致前端和后端分别占用不同的端口,所以浏览器在访问不同接口的时候就会存在跨域问题。

解决方法

我是在springboot后端项目中添加CorsConfig配置类,用于解决跨域问题,当然前端也可以解决这个跨域问题。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
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;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration
public class corsConfig {@Beanpublic WebMvcConfigurer CORSConfigurer() {return new WebMvcConfigurerAdapter() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*")//设置是否允许跨域传cookie.allowCredentials(true)//设置缓存时间,减少重复响应.maxAge(3600);}};}@Beanpublic FilterRegistrationBean corsFilter() {final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();final CorsConfiguration config = new CorsConfiguration();// 允许cookies跨域config.setAllowCredentials(true);// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Originconfig.addAllowedOrigin("*");// #允许访问的头信息,*表示全部config.addAllowedHeader("*");// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了config.setMaxAge(3600L);// 允许提交请求的方法,*表示全部允许config.addAllowedMethod("OPTIONS");config.addAllowedMethod("HEAD");config.addAllowedMethod("GET");config.addAllowedMethod("PUT");config.addAllowedMethod("POST");config.addAllowedMethod("DELETE");config.addAllowedMethod("PATCH");source.registerCorsConfiguration("/**", config);FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));// 设置监听器的优先级bean.setOrder(0);return bean;}
}

这样就能解决前后端跨域问题。

2、后端存储的session,前端获取不到

起因是我在做登录的时候,用户信息被我用session存储在了后端,但是我在调用其他接口的时候,我却无法在后端获取到我保存在后端的用户信息,无法判断前端是否登录过。

这个问题一开始困扰了我很久,搜了半天发现了一个不错的解释:这是因为服务器判断前端的请求是同一个 session 的依据是通过网页默认的一个sessionid的cookie判断的,如果存在跨域,cookie值传不过来,也就当下一个请求过来时服务端无法识别为同一个会话,会被当做一个新的会话处理,故找不到session原保存的值。
在这里插入图片描述
所以我就去测试两个不同请求的sessionId是否是一样的,发现果然不一样,这也是为什么我在后端无法获取到我保存在后端的session。

解决方法

其实解决办法有很多种,例如说不用session存储数据而是利用Redis,这当然是最轻松的方式。但是本着我的session是利用shiro自带的Util存储的,所以我的解决方式是将sessionId回传给前端,然后前端保存后每次访问后端接口的时候携带保存的sessionId,这样就能我就能获取到原来的session了。

1、在登录接口中将sessionId回传给前端

public ResponseResult doLogin(String username, String password) {UsernamePasswordToken token = new UsernamePasswordToken(username,password);Subject subject = SecurityUtils.getSubject();try{subject.login(token);UserInfo userInfo = baseMapper.selectById(username);//利用shiro的Util获取sessionIdString sessionId = (String) subject.getSession().getId();//存储用户信息ShiroUtils.setSessionAttribute(SessionConst.USER_INFO_SESSION,userInfo);System.out.println((String)ShiroUtils.getSession().getId());userInfo.setSalt("");userInfo.setPassword("");Map<String,Object> data = new HashMap<>();//保存key-value类型数据AUTHORIZATION,值为sessionIddata.put("AUTHORIZATION", sessionId);data.put("userInfo",userInfo);//回传给前端return ResponseResult.success(data);}catch(UnknownAccountException e){return ResponseResult.error(ResponseResultEnum.SESSION_ERROR);}catch (IncorrectCredentialsException e){return ResponseResult.error(ResponseResultEnum.PASSWORD_ERROR);}
}

前端拿到sesionId后进行保存,并每次调用接口的时候携带Id即可

//举例:登录method
login() {this.$axios.get("/login", {params: {username: this.form1Data.username,password: this.form1Data.password}}).then((res) => {if (res.data.code === 200) {console.log(res)var userInfo = res.data.data.userInfovar auth = res.data.data.AUTHORIZATIONElementUI.Message.success("登录成功");this.$store.commit("SET_USERINFO", userInfo);//将信息保存在auth中this.$store.commit("SET_AUTH", auth)let url_name = this.$route.params.redirectconsole.log(url_name)if (url_name !== undefined && url_name !== null && url_name != '') {this.$router.replace({name: url_name})} elsethis.$router.push('/')} else { // 有问题ElementUI.Message.error(res.data.message);}})
}//在main.js文件中进行前置拦截
axios.interceptors.request.use(config => {let auth = store.getters.get_auth//从auth中获取后端传给前端的sessionId,以后调用任何接口就可以携带sessionId了if (auth != null) {config.headers['AUTHORIZATION'] = auth;}console.log(config.headers)return config;}, error => {return Promise.reject(error)
});

2、在配置类中写一个自定义的sessionManager并重写getSessionId方法,便于对前端传递过来的sessionId进行判断,检测是否是原来的sessionId。

@Configuration
@Slf4j
public class MySessionManager extends DefaultWebSessionManager {private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";public MySessionManager() {super();}@Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {String id = WebUtils.toHttp(request).getHeader("AUTHORIZATION");//如果请求头中有 Authorization (前端请求头中设置的名字)则其值为sessionIdif (!StringUtils.isEmpty(id)) {request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return id;} else {//否则按默认规则从cookie取sessionIdreturn super.getSessionId(request, response);}}
}

3、在shiro配置类中注入自定义的session缓存管理器

@Bean("sessionManager")
public SessionManager sessionManager(){MySessionManager sessionManager = new MySessionManager();sessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());sessionManager.setGlobalSessionTimeout(1000 * 60 * 30);sessionManager.setSessionValidationSchedulerEnabled(true);sessionManager.setSessionIdUrlRewritingEnabled(false);return sessionManager;
}

关键: 因为getSessionId()方法是通过DefaultWebSecurityManager类进行实现的,所以我们需要将SessionManager注入到安全管理中

/*** 安全管理** @return*/
@Bean
public DefaultWebSecurityManager securityManager(){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//注入securityManager.setSessionManager(sessionManager());securityManager.setRealm(getShiroRealm());return securityManager;
}

至此可解决前后端跨域后的sessionId的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/630772.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker本地私有仓库搭建配置指导

一、说明 因内网主机需要拉取镜像进行Docker应用&#xff0c;因此需要一台带外主机作为内网私有仓库来提供内外其他docker业务主机使用。参考架构如下&#xff1a; 相关资源&#xff1a;加密、Distribution registry、Create and Configure Docker Registry、Registry部署、D…

K8s-架构

一、K8s节点划分 K8s集群包含Master(控制节点)和Node(工作节点)&#xff0c;应用部署在Node节点上。 集群架构图&#xff1a; 二、Master节点 Master节点分成四个组件&#xff1a;scheduler、ApiServer、Controller Manager、ETCD。类似三层结构&#xff0c;controller&#…

2024年外贸新兴市场有哪些 | 箱讯科技国际贸易平台

当前欧美市场经济增速放缓&#xff0c;通胀持续高位导致物价普遍上涨&#xff0c;进一步引发消费疲软。此外&#xff0c;受原材料价格、劳动力、土地等经营成本上升影响&#xff0c;外贸出口企业利润被进一步压缩。 困顿之中&#xff0c;新兴市场成为破局关键&#xff0c;巨大的…

Mysql流程控制函数

1概述 Mysql中的流程控制函数非常重要&#xff0c;可以根据不同的条件&#xff0c;执行不同的流程转换&#xff0c;可以在SQL语句中实现不同的条件选择。MySQL中的流程处理函数主要包括IF()、IFNULL()和CASE()函数。 1.1 IF函数 SELECT IF(1 > 0, 正确, 错误);1.2 IFNULL…

rabbitmq基础教程(ui,java,springamqp)

概述&#xff1a;安装看我上篇文章Docker安装rabbitmq-CSDN博客 任务一 创建一个队列 这样创建两个队列 在amq.fanout交换机里面发送数据 模拟发送数据 发送消息&#xff0c;发现一下信息&#xff1a; 所以得出理论&#xff0c;消息发送是先到交换机&#xff0c;然后由交换机…

如何手写一个RPC?

在学习 RPC 框架之前&#xff0c;我们先来手写一个RPC。 我们在学习的过程中&#xff0c;一定要做到知其然&#xff0c;还要知其所以然。 架构演进 单体架构 要知道&#xff0c;在以前单体架构的时候&#xff0c;会将所有的应用功能都集中在一个服务当中。 单体架构初始开发…

新版K8s:v1.28拉取Harbor仓库镜像以及本地镜像(docker弃用改用containerd,纯纯踩坑)

目录 一、项目概述二、环境三、项目样式Harborkuboard运行样式 四、核心点Harbor安装config.toml文件修改(containerd)ctr、nerdctl相关命令kuboard工作负载 五、总结 一、项目概述 使用Kuboard作为k8s集群的管理平台&#xff0c;Harbor作为镜像仓库&#xff0c;拉取Harbor镜像…

HttpServletRequest getServerPort()、getLocalPort() 、getRemotePort() 区别

getRemotePort() 、getServerPort()、getLocalPort() request.getServerPort()、request.getLocalPort() 和 request.getRemotePort() 这三个方法都是获取与HTTP请求相关的端口信息的 客户端(如浏览器)通过某个随机分配的网络连接端口(7070) 向服务器发送HTTP请求( http://exam…

异次元发卡最新0day(XSS组合拳)

异次元商店头像上传处存在存储型XSS注入&#xff08;user、admin均存在&#xff09;。其中&#xff0c;user处有过滤&#xff0c;admin无。 将恶意脚本插入后&#xff0c;管理员访问用户管理页面即可执行恶意脚本。 恶意脚本执行后&#xff0c;会新增一个管理员用户&#xff0c…

HBase学习二:RegionServer详解

1、内部结构 RegionServer是HBase系统中最核心的组件,主要负责用户数据写入、读取等基础操作。RegionServer组件实际上是一个综合体系,包含多个各司其职的核心模块:HLog、MemStore、HFile以及BlockCache。 一个RegionServer由一个(或多个)HLog、一个BlockCache以及多个R…

构建中国人自己的私人GPT—限时免费部署

在现实生活中&#xff0c;很多公司或个人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的本地专属GPT变得非常重要。 先看效果&#xff1a; 解方程&#xff0c;24小…

小程序中使用上传图片,显示、删除、预览

一、功能介绍 需要哦用户点击加号上传图片&#xff0c;并展示所上传图片和能够删除和预览 二、功能实现 采用的uniapp&#xff0c;创建了一个view容器包裹加号图标和展示的图片。 内部展示图片超过9张时候&#xff0c;加号图片隐藏 <view class"img-list">/…

RK3399平台入门到精通系列讲解(USB篇)UDC 层 usb_gadget_probe_driver 接口分析

🚀返回总目录 文章目录 一、UDC:usb_gadget_probe_driver函数分析二、usb_gadget_driver 结构详细介绍三、usb_udc 结构详细介绍一、UDC:usb_gadget_probe_driver函数分析 UDC层的一项基本任务是向上层提供usb_gadget_probe_driver()接口函数。 上层调用者为composite.c中…

JVM工作原理与实战(十八):运行时数据区-堆

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、运行时数据区 二、堆 1.堆介绍 2.关键参数 总结 前言 ​JVM作为Java程序的运行环境&#xff0c;其负责解释和执行字节码&#xff0c;管理内存&#xff0c;确保安全&#xff0c…

清晰光谱空间:全自动可调波长系统的高光谱成像优势

高光谱成像技术 高光谱成像技术是一种捕获和分析宽波长信息的技术&#xff0c;能够对材料和特征进行详细的光谱分析和识别。高光谱成像技术的实现通过高光谱相机&#xff0c;其工作原理是使用多个光学传感器或光学滤波器分离不同波长的光&#xff0c;并捕获每个波段的图像&…

web蓝桥杯真题--9、水果拼盘

介绍 目前 CSS3 中新增的 Flex 弹性布局已经成为前端页面布局的首选方案&#xff0c;本题可以使用 Flex 属性快速完成布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └── style.css ├── im…

『 C++ 』红黑树RBTree详解 ( 万字 )

文章目录 &#x1f996; 红黑树概念&#x1f996; 红黑树节点的定义&#x1f996; 红黑树的插入&#x1f996; 数据插入后的调整&#x1f995; 情况一:ucnle存在且为红&#x1f995; 情况二:uncle不存在或uncle存在且为黑&#x1f995; 插入函数代码段(参考)&#x1f995; 旋转…

appium之联动pycharm

前置条件&#xff1a; 1.java环境安装好了 2.android-sdk安装好&#xff08;uiautomatorviewer 也可以把这个启动起来&#xff09; 3.appium安装好 4.adb devices查看下设备是否连接 pycharm入门代码--固定写法 from appium import webdriver# 定义字典变量 desired_caps …

脱离outlook的OST邮件缓存文件查看与转化PST文件教程

对于已经登录了outlook客户端且能正常收发邮件的&#xff0c;可以直接在outlook查看邮件内容和通过outlook转化为可被直接打开的pst备份文件。但对于因服务器故障或者临时拷贝备份的ost文件&#xff0c;因没有通过outlook账户类型的认证&#xff0c;是不能直接用outlook客户端打…

海外购物商城源码 带即时通讯IM源码

海外购物商城源码- 即时通讯IM源码 随着电子商务的快速发展和全球化趋势的增强&#xff0c;越来越多的消费者选择海外购物商城。海外购物商城提供了丰富的商品种类和品牌&#xff0c;满足了消费者对高质量、多样化商品的需求。而且&#xff0c;它还提供了更方便的购物体验&…