SpringBoot+vue前后端分离整合sa-token(无cookie登录态 详细的登录流程)

SpringBoot+vue前后端分离整合sa-token(无cookie登录态 & 详细的登录流程)

  • 1.介绍sa-token
    • 1.1 框架定位
    • 1.2 核心优势
  • 2.如何整合sa-token
  • 3.如何进行无cookie模式登录
    • 3.1后端
      • 3.1.1 VO层
      • 3.1.2 Controller层
      • 3.1.3 Service层
    • 3.2前端
      • 3.2.1 登录按钮
      • 自定义axios
  • 4.验证
    • 4.1验证前的最后准备
    • 4.2 验证结果
  • 5.结语

😀大家好!我是向阳🌞,一个想成为优秀全栈开发工程师的有志青年!	
📔今天来说一说如何来编写SpringBoot+vue前后端分离整合sa-token(无cookie登录态)。

1.介绍sa-token

在这里插入图片描述


https://sa-token.cc/doc.html#/

1.1 框架定位

Sa-Token 是一款面向Java开发者的轻量级权限认证框架,专为现代化应用设计。其核心价值在于:

  • 🚀 极简API设计:5分钟快速接入,10行代码完成基础权限控制
  • 🛡️ 全场景支持:覆盖会话管理、权限认证、单点登录、OAuth2.0等常见安全场景
  • 🌐 跨端适配:完美支持前后端分离架构,原生适配APP、小程序等非Web环境
  • 📦 轻量无依赖:核心包仅700KB,无需额外依赖,拒绝臃肿

1.2 核心优势

相较于Spring Security、Shiro等传统方案,Sa-Token具有以下突破性优势:

特性Sa-Token传统方案
学习成本★★☆☆☆★★★★★(陡峭)
RESTful支持原生适配需要复杂配置
前后端分离支持开箱即用需自定义解决方案
注解鉴权声明式注解需编写拦截器逻辑
分布式会话一行代码依赖外部存储

还有一些创新特性,我简单列举几点,剩下的大家可以到官方文档(链接:Sa-Token)中看:

  • 无Cookie会话管理:原生支持Token认证模式,完美适配APP、小程序等移动端场景
  • 动态权限刷新:权限修改实时生效,无需用户重新登录
  • 踢人下线:精准控制账号登录状态,支持根据设备维度下线
  • 临时令牌:支持临时Token颁发,适用于第三方授权等场景
  • 二级认证:敏感操作时进行二次验证,提升系统安全性

2.如何整合sa-token

本项目是SpringBoot3.x版本,如果您是2.x版本请注意版本问题

1.首先在maven中引入依赖

<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot3-starter</artifactId><version>1.41.0</version>
</dependency>

如果你是spring boot2.x版本请引入

<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.41.0</version>
</dependency>

2.然后配置对应的yml文件(这只是官方给的默认的配置,后面咱们需要修改)

############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
sa-token: # token 名称(同时也是 cookie 名称)token-name: satoken# token 有效期(单位:秒) 默认30天,-1 代表永久有效timeout: 2592000# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结active-timeout: -1# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)is-share: false# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)token-style: uuid# 是否输出操作日志 is-log: true

3.如何进行无cookie模式登录

首先我们要对官方文档给出的一些方法进行了解。

// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id);     // 当前会话注销登录
StpUtil.logout();// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();

我们暂且了解这么多方法就够了,我们只要知道,通过login方法可以给我们返回一个token来作为唯一凭证进行登录,返回的token格式可以在yml配置文件中配置,官方文档默认设置的是uuid,后面我会来带大家集成 jwt,让我们的token更加安全。

3.1后端

我们导入以来后,接下来我们来进行编写我们的后端代码。首先我们要做的是无cookie登录态,我们先到配置文件中修改一下我们的配置。

sa-token:# token 名称(同时也是 cookie 名称)token-name: token# 其他配置默认不变......# 添加下面两个配置,关闭cookie读取,通过请求头读取# 关闭 Cookie 读取is-read-cookie: false# 开启 Header 读取is-read-header: true

3.1.1 VO层

接下来,我们要在登录的接口中要返回StpUtil.login方法给出的token值,我们要在返回的UserVO对象中添加SaTokenInfo对象,这个SaTokenInfo对象里面就是这个token值的一些信息(或者你可以添加一个字符串tokenValue,都是可以的,看你自己的需求

@Data
public class UserVO implements Serializable {/*** id*/private Long id;/*** 用户昵称*/private String userName;/*** 账号*/private String userAccount;/*** 访问令牌*/private SaTokenInfo saTokenInfo;private static final long serialVersionUID = 1L;
}

3.1.2 Controller层

一些提示:

  • UserLoginRequest只是一个封装类,里面就两个参数,一个账号一个密码。
  • ThrowUtils.throwIf是博主自己封装的一个方法,用来抛出异常类,你直接Throw一个异常类就可以。当然这里抛出的全局异常,感兴趣的话可以看博主的这边文章(SpringBoot如何配置全局异常处理器)
  • 返回的BaseResponse是统一了响应体返回,感兴趣也是看上面那个链接(SpringBoot如何配置全局异常处理器),你也可以直接返回UserVO,但是报错了之后就没有那么美观了。
  • 返回的ResultUils.success也是一个工具类,实际上就是new了一个BaseResponse类返回。
/*** 用户登录** @param userLoginRequest* @param request* @return*/@PostMapping("/login")public BaseResponse<UserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR);String userAccount = userLoginRequest.getUserAccount();String userPassword = userLoginRequest.getUserPassword();if (StringUtils.isAnyBlank(userAccount, userPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}UserVO userVO = userService.userLogin(userAccount, userPassword, request);return ResultUtils.success(userVO);}

3.1.3 Service层

接下来我们进入到userLogin方法看看发生了什么。

流程分析以及一些提示:

  • 首先就是校验参数是否正确,不正确则抛出异常。
  • 因为存储在数据库中的密码肯定是加密过的嘛,所以我们要先对传过来的密码进行加密,然后进行对比。
  • 查询用户如果存在,则调用StpUtil.login(user.getId())进行登录,否则报错。注意,我们调用login方法的时候参数要传一个唯一值,这样每个用户才会拥有自己独有的token。假如你拿性别作为条件传进去,那么一半一半的用户使用的都是同一个token值,那岂不是很恐怖了😥。
  • 最后的返回值调用了 getUserVOInfo 方法,这个方法就是将User类转为UserVO类,并且把产生的 tokeninfo set进去,代码我也给大家贴了。
	@Overridepublic UserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {// 1. 校验if (StringUtils.isAnyBlank(userAccount, userPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");}ThrowUtils.throwIf(userAccount.length() < 4, ErrorCode.PARAMS_ERROR, "账号错误");ThrowUtils.throwIf(userPassword.length() < 8, ErrorCode.PARAMS_ERROR, "密码错误");// 2. 加密String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());// 查询用户是否存在QueryWrapper<User> queryWrapper = new QueryWrapper();queryWrapper.eq("userAccount", userAccount);queryWrapper.eq("userPassword", encryptPassword);User user = userMapper.selectOne(queryWrapper);// 用户不存在ThrowUtils.throwIf(user == null, ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");// 3. 用户登录try {StpUtil.login(user.getId());} catch (Exception e) {throw new BusinessException(ErrorCode.SYSTEM_ERROR, "网络超时");}// 将token 信息返回给前端return getUserVOInfo(user);}@Overridepublic UserVO getUserVOInfo(User user) {UserVO userVO = new UserVO();BeanUtils.copyProperties(user, userVO);userVO.setSaTokenInfo(StpUtil.getTokenInfo());return userVO;}

3.2前端

我们来进行前端的书写,前端的逻辑最主要的就是两点。

  1. 在点击登录按钮的时候,调用后端书写的接口,我们要保存返回的token值到本地。
  2. 我们每次调用请求的时候都在请求头上携带上这个token值,这样后端就能认出我们是谁了。

话不多说,我们直接开干。

3.2.1 登录按钮

逻辑分析以及一些提示:

  • 我们在点击按钮后,调用后端登录的接口,这里的方法都是封装好的,因为是通过一个插件生成的这些方法,感兴趣的同学了解一下这篇文章(一键生成后端的请求接口)
  • 调用成功后,我们获取到返回值中的token,并存到本地。
/*** 登录按钮* @returns {Promise<void>}*/
const handleSubmit = async () => {const res = await userLogin(form)if (res.data.code === 0 && res.data.data) {const tokenValue = res.data.data.saTokenInfo.tokenValuelocalStorage.setItem('token', tokenValue)await loginUserStore.fetchLoginUser()message.success('登录成功')router.push({path: '/',replace: true,})} else {message.error('登录失败,' + res.data.message)}
}

自定义axios

主要介绍在请求拦截器中的代码。

逻辑分析以及一些提示:

  • 核心点就是在每次发起请求前,请求头当中携带上我们保存的token值。
// 创建 Axios 实例
const myAxios = axios.create({baseURL: 写你的后端请求地址,timeout: 60000,withCredentials: false, // 不使用cookie来存储登录态,所以关闭
})
// 全局请求拦截器
myAxios.interceptors.request.use(function (config) {// Do something before request is sentconst tokenValue = localStorage.getItem('token')config.headers['token'] = tokenValuereturn config},function (error) {// Do something with request errorreturn Promise.reject(error)},
)

4.验证

4.1验证前的最后准备

到这里,我们就已经做完全部工作了,我们通过前端登录来进行验证,当然我们还需要补充一个验证是否登录成功的方法,这里我们就使用 isLogin 方法来进行验证,我们通过Knife4j来调用这个方法验证是否成功登录。(有感兴趣的同学可以了解博博主的另另另一篇文章:SpringBoot整合Knife4j)。

	@Overridepublic UserVO getLoginUser(HttpServletRequest request) {// 直接通过 Sa-Token 获取登录IDif (!StpUtil.isLogin()) {throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);}// 从数据库查询 下面的代码可以忽略掉...Long userId = StpUtil.getLoginIdAsLong();User user = this.getById(userId);if (user == null) {throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);}return this.getUserVOInfo(user);}

4.2 验证结果

我们登录后可以看到响应体的返回值中携带了token的信息,其中tokenValue就是我们需要的token值。这里博主的tokenValue复杂是因为博主整合了jwt,下一篇文章来带大家整合!
在这里插入图片描述
并且到浏览器本地查看是否存储了token值,可以看到是缓存到浏览器里面的,并且没有携带cookie

在这里插入图片描述
在这里插入图片描述
在调用登录后,我们进入到主页时,我调用了获取用户登录状态的信息,发现也是调用成功,至此,我们的登录流程已经完满结束。
在这里插入图片描述
在这里插入图片描述

5.结语

本章让大家了解并认识了sa-token这个框架,这个使用起来简单上手,使用起来也很便捷,接下来我会持续更新这个框架的一些东西,有感兴趣的小伙伴可以持续关注博主的博客。

(预告)在下篇章节中,我们将介绍JWT,整合JWT来生成更安全的token值。还有一个问题,我们在每次重启项目后我们就需要重新登录,我们该如何解决这个问题呢?接下来我会带大家一一解决。
请添加图片描述

——👦[作者]:向阳256
——⏳[更新]:2025.4.3
——🥰本人技术有限,如果有不对指正需要更改或者有更好的方法,欢迎到评论区留言。

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

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

相关文章

MYOJ_1171:(洛谷P1075)[NOIP 2012 普及组] 质因数分解(数学相关,质数与约数基础)

题目描述 已知正整数 n 是两个不同的质数的乘积&#xff0c;试求出两者中较大的那个质数。 1≤n≤210^9 输入 输入一个正整数 n。 输出 输出一个正整数 p&#xff0c;即较大的那个质数。 样例输入输出 输入&#xff1a;21 输出&#xff1a;7 思路: 为了节约时间与…

Python语言的测试用例设计

Python语言的测试用例设计 引言 随着软件开发的不断进步&#xff0c;测试在软件开发生命周期中的重要性日益凸显。测试用例设计是软件测试的核心&#xff0c;它为软件系统的验证和验证提供了实施的基础。在Python语言中&#xff0c;由于其简洁明了的语法和强大的内置库&#…

SpringKafka消息消费:@KafkaListener与消费组配置

文章目录 引言一、Spring Kafka消费者基础配置二、KafkaListener注解使用三、消费组配置与负载均衡四、手动提交偏移量五、错误处理与重试机制总结 引言 Apache Kafka作为高吞吐量的分布式消息系统&#xff0c;在大数据处理和微服务架构中扮演着关键角色。Spring Kafka为Java开…

VMware 虚报化Ubuntu 卡成一B,如何接招?

故事背景 Win10 专业版 安装VMware pro ,虚拟化出一个Window10&#xff0c;另一个是UBuntu.自从使用起来去不去就卡死。开始是以为驱动或者升级造成的&#xff0c;重新安装一段时间问题照旧。更气人的这种现象具有不定期性&#xff0c;说不定什么时候就来这么一出。 直接解决方…

cloud项目批量修改主机号

当clone了一个cloud项目后&#xff0c;要把别人的主机号全部改成自己的&#xff0c;非常麻烦 在项目根目录下&#xff0c;启动 Git Bash。在 Git Bash 终端中使用原始的 Unix 命令&#xff1a; find . -type f -exec sed -i s/127\.0\.0\.1/132.168.190.163/g {} 其中127.0.…

微信小程序使用 Vant Weapp 组件库教程

在微信小程序项目中使用 Vant 组件库&#xff08;Vant Weapp&#xff09;主要包括以下几个步骤&#xff1a; 1. 初始化项目并安装 Vant Weapp 初始化 npm 在项目根目录下运行以下命令&#xff0c;生成 package.json&#xff1a; npm init -y安装 Vant Weapp 执行以下命令安装 V…

FPGA状态机思想实现流水灯及HDLBits学习

目录 第一章 在DE2-115上用状态机思想实现LED流水灯1.1 状态机设计思路1.2 Verilog代码实现1.3. 仿真测试代码1.4 编译代码与仿真 第二章 CPLD和FPGA芯片的主要技术区别是什么&#xff1f;它们各适用于什么场合&#xff1f;2.1 主要技术区别2.2 适用场合 第三章 HDLBits学习3.1…

与总社团联合会合作啦

2025.4.2日&#xff0c;我社团向总社团联合会与暮光社团发起合作研究“浔川代码编辑器v2.0”。至3日&#xff0c;我社团收到回复&#xff1a; 总社团联合会&#xff1a; 总社团联合会已收到浔川社团官方联合会的申请&#xff0c;经考虑&#xff0c;我们同意与浔川社团官方联合…

Shiro学习(三):shiro整合springboot

一、Shiro整合到Springboot步骤 1、准备SpringBoot 环境&#xff0c;这一步省略 2、引入Shiro 依赖 因为是Web 项目&#xff0c;所以需要引入web 相关依赖 shiro-spring-boot-web-starter&#xff0c;如下所示&#xff1a; 3、准备Realm 因为实例化 ShiroFilterFactoryBean 时…

【图形API】片段着色器自动计算LOD

片段着色器中的自动 LOD 计算详解 在图形渲染中&#xff0c;Level of Detail (LOD) 用于优化纹理采样的性能和视觉质量。片段着色器&#xff08;Fragment Shader&#xff09;能够自动计算 LOD&#xff0c;而顶点着色器&#xff08;Vertex Shader&#xff09;则不行。以下是详细…

24、 Python Socket编程:从协议解析到多线程实战

Python Socket编程&#xff1a;从协议解析到多线程实战 一、文章概述 本文深入讲解Python网络编程核心技术&#xff0c;涵盖TCP/UDP协议底层原理、Socket API全流程解析、高并发服务端开发实践&#xff0c;以及网络通信中的典型问题解决方案。通过3个递进式代码案例和协议设计…

LabVIEW 中数字转字符串常用汇总

在 LabVIEW 编程环境里&#xff0c;数字与字符串之间的转换是一项极为基础且重要的操作&#xff0c;广泛应用于数据处理、显示、存储以及设备通信等多个方面。熟练掌握数字转字符串的方法和技巧&#xff0c;对编写高效、稳定的程序起着关键作用。接下来&#xff0c;我们将全面深…

轨迹速度聚类 实战

根据轨迹把速度聚类为3个类别,速度快的那部分不用平滑,速度慢的部分需要平滑。 速度聚类3个类别: kmeans++ import numpy as np import cv2 from sklearn.cluster import KMeans from matplotlib.colors import hsv_to_rgb from scipy.ndimage import gaussian_filter1d# …

vulkanscenegraph显示倾斜模型(5.6)-vsg::RenderGraph的创建

前言 上一章深入分析了vsg::CommandGraph的创建过程及其通过子场景遍历实现Vulkan命令录制的机制。本章将在该基础上&#xff0c;进一步探讨Vulkan命令录制中的核心封装——vsg::RenderGraph。作为渲染流程的关键组件&#xff0c;RenderGraph封装了vkCmdBeginRenderPass和vkCmd…

第二十八章:Python可视化图表扩展-和弦图、旭日图、六边形箱图、桑基图和主题流图

一、引言 在数据可视化领域&#xff0c;除了常见的折线图、柱状图和散点图&#xff0c;还有一些高级图表类型可以帮助我们更直观地展示复杂数据关系。本文将介绍五种扩展图表&#xff1a;和弦图、旭日图、六边形箱图、桑基图和主题流图。这些图表在展示数据关系、层次结构和流量…

大模型-爬虫prompt

爬虫怎么写prompt 以下基于deepseek r1 总结&#xff1a; 以下是为大模型设计的结构化Prompt模板&#xff0c;用于生成专业级网络爬虫Python脚本。此Prompt包含技术约束、反检测策略和数据处理要求&#xff0c;可根据具体需求调整参数&#xff1a; 爬虫脚本生成Prompt模板1 …

Vue中将pdf文件转为图片

平时开发中,我们经常遇到的场景应该是调用后端接口返回给前端pdf格式的文件流,然后我们可以通过URL.createObjectURL的方式转为object url临时路径然后可以通过window.open的方式来打开一个新的浏览器页签来进行预览,效果如下图: 但有时候这样满足不了的需求,它不想这样预…

物联网安全技术:守护智能世界的防线

最近研学过程中发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…

kubernetes安装部署k8s

kubernetes https://github.com/kubernetes/kubernetes.git go mod tidy go mod vendor go build -o .\bin -v ./… //手动创建bin文件夹 使用 minikube&#xff1a;https://gitee.com/mirrors/minikube.git 使用minikube启动本地化的集群服务 minikube start 启动集群&…

JT/T 1078 协议基本介绍与解析

文章目录 一、JT/T 1078 协议基本介绍二、JT/T 1078 与 JT808 的关系三、JT1078 协议核心功能四、JT1078 数据结构概览4.1、消息结构&#xff1a;4.2、消息类型&#xff08;部分&#xff09;&#xff1a; 五、Java 中如何解析 JT1078 协议数据&#xff1f;5.1、JT1078 消息 ID …