当前位置: 首页 > news >正文

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.mrgr.cn/news/97021.html

相关文章:

  • TRDI 公司的RiverPro 和 RioPro ADCP 用户指南
  • 生成对抗网络(GAN)详解(代码实现)
  • 【C++】Cplusplus进阶
  • 2025徘徊与坚守:在传统与变革间寻找自己
  • 基于卷积神经网络CNN实现电力负荷多变量时序预测(PyTorch版)
  • RabbitMQ高级特性1
  • lodash库介绍(一个现代JavaScript实用工具库,提供模块化、性能优化和额外功能)JavaScript库(防抖、节流、函数柯里化)JS库
  • 【从零实现Json-Rpc框架】- 项目实现 - 服务端主题实现及整体封装
  • 前端Uniapp接入UviewPlus详细教程!!!
  • [Linux]从零开始的vs code交叉调试arm Linux程序教程
  • 容器的CPU
  • CAD插入属性块 弹窗提示输入属性值——CAD知识讲堂
  • GenerationMixin:_sample方法(GenerationMode.SAMPLE, GenerationMode.GREEDY_SEARCH)
  • [C语言入门] 结构体
  • 接口自动化学习二:session自动管理cookie
  • Maven+Spring实现后端开发
  • Pytorch中预置数据集的加载方式
  • 数据结构学习
  • 大模型学习二:DeepSeek R1+蒸馏模型组本地部署与调用
  • 【MyBatis】深入解析 MyBatis:关于注解和 XML 的 MyBatis 开发方案下字段名不一致的的查询映射解决方案