ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Sa-Token 前后端分离鉴权实战:无 Cookie 模式下 Token 的下发、存储与提交

2026/9/13 16:38:04 拓冰建站 浏览量
Sa-Token 前后端分离鉴权实战:无 Cookie 模式下 Token 的下发、存储与提交 Sa-Token 前后端分离鉴权实战无 Cookie 模式下 Token 的下发、存储与提交【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token在 App、小程序、以及前后端分离的 Web 场景中终端往往不支持 Cookie 或不便依赖 Cookie 自动携带凭证这使得传统后端写 Cookie、浏览器自动带的鉴权方式失效。本文以 Sa-Token 官方文档 前后端分离无Cookie模式 为骨架结合核心源码与官方示例完整讲解后端如何把 Token 下发到前端、前端如何存储与提交 Token、后端如何再次读取 Token的整套闭环并给出可直接落地的 uni-app 请求封装方案。读完本文你将能在不依赖 Cookie 的任意终端App、小程序、分离式 Web、Hybrid上完整跑通 Sa-Token 的登录与鉴权流程。一、何为无 Cookie 模式无 Cookie 模式特指不支持 Cookie 功能的终端场景通俗来讲就是我们常说的前后端分离模式。常规 Web 端鉴权一般由Cookie 模式完成。Cookie 有两个关键特性可由后端控制写入后端在响应中下发Set-Cookie浏览器自动保存每次请求自动提交浏览器在同域请求中自动携带 Cookie前端无需任何代码参与。正是这两个特性使得传统 PC 端在前端零代码介入的情况下就能完成鉴权的全部流程整个流程均由后端控制。而在 App、小程序等前后端分离场景中一般没有 Cookie 这一功能。此时如何鉴权见招拆招答案其实很简单只需要把 Cookie 的两个特性手动化Cookie 特性分离模式下对应的解法核心难点后端控制写入前端自己写入存储到本地后端如何将 Token 传递到前端请求自动提交前端手动提交塞进 Header前端如何提交 Token以及后端如何将其读取出来整个无 Cookie 模式的实现就是围绕上面两个难点展开的。二、后端将 Token 返回到前端2.1 两步核心操作首先调用StpUtil.login(id)完成登录调用StpUtil.getTokenInfo()获取当前会话的 Token 详细参数。getTokenInfo()返回一个SaTokenInfo对象其中有两个关键属性tokenName和tokenValue即Token 的名称和Token 的值。将此对象返回给前端让前端把这两个值保存到本地即可。2.2 登录接口代码示例// 登录接口 RequestMapping(doLogin) public SaResult doLogin() { // 第1步先登录上 StpUtil.login(10001); // 第2步获取 Token 相关参数 SaTokenInfo tokenInfo StpUtil.getTokenInfo(); // 第3步返回给前端 return SaResult.data(tokenInfo); }仓库中的官方示例 NotCookieController.java 给出了更完整的对比写法doLogin是前后端一体模式登录后仅返回SaResult.ok()Token 由后端写入 Cookie而doLogin2是前后端分离模式——登录后通过SaResult.data(tokenInfo)把SaTokenInfo整体塞进响应体返回给前端。两者的差别正是是否主动下发 Token 信息。2.3 SaTokenInfo 对象各字段详解SaTokenInfo定义于 SaTokenInfo.java它描述了一个 Token 的全部常见参数。以源码中的 Javadoc 示例为参照一次典型的返回结构如下{ tokenName: satoken, tokenValue: e67b99f1-3d7a-4a8d-bb2f-e888a0805633, isLogin: true, loginId: 10001, loginType: login, tokenTimeout: 2591977, sessionTimeout: 2591977, tokenSessionTimeout: -2, tokenActiveTimeout: -1, loginDeviceType: DEF }各字段含义依据源码字段定义与注释字段含义说明tokenNameToken 名称即全局配置项token-name默认值为satokentokenValueToken 值当前会话的 Token 值isLogin此 Token 是否已登录true/falseloginId此 Token 对应的账号 ID未登录时为nullloginType账号类型标识多账号体系下区分不同账号体系默认logintokenTimeoutToken 剩余有效期秒-1代表永久有效-2代表值不存在sessionTimeoutAccount-Session 剩余有效时间秒同上约定tokenSessionTimeoutToken-Session 剩余有效时间秒-2表示系统中不存在这个缓存tokenActiveTimeoutToken 距离被冻结还剩多少时间秒即无操作冻结机制的剩余活跃时间loginDeviceType登录设备类型默认DEF可配合同端互斥登录使用提示前端真正必需保存的只有tokenName与tokenValue两个字段其余字段可用于展示登录状态、剩余有效期等信息。三、前端将 Token 提交到后端无论是 App 还是小程序Token 的传递方式都大同小异将 Token 塞到请求的Header里格式为{tokenName: tokenValue}。以经典跨端框架uni-app为例官方文档提供了两种实现方式。3.1 方式一简单粗暴只存 tokenValue把tokenValue存到本地发起请求时硬编码 header 参数名注意此处参数名是satoken与默认tokenName保持一致// 1、首先在登录时将 tokenValue 存储在本地例如 uni.setStorageSync(tokenValue, tokenValue); // 2、在发起ajax请求的地方获取这个值并塞到header里 uni.request({ url: https://www.example.com/request, // 仅为示例并非真实接口地址。 header: { content-type: application/x-www-form-urlencoded, satoken: uni.getStorageSync(tokenValue) // ⚠️ 关键代码, 注意参数名字是 satoken }, success: (res) { console.log(res.data); } });3.2 方式二更加灵活tokenName 与 tokenValue 一起存把tokenName和tokenValue都存入本地发起请求时动态组装 headerheader 参数名完全跟随后端配置更通用、更不易出错// 1、首先在登录时将tokenName和tokenValue一起存储在本地例如 uni.setStorageSync(tokenName, tokenName); uni.setStorageSync(tokenValue, tokenValue); // 2、在发起ajax的地方获取这两个值, 并组织到head里 var tokenName uni.getStorageSync(tokenName); // 从本地缓存读取tokenName值 var tokenValue uni.getStorageSync(tokenValue); // 从本地缓存读取tokenValue值 var header { content-type: application/x-www-form-urlencoded }; if (tokenName ! undefined tokenName ! ) { header[tokenName] tokenValue; } // 3、后续在发起请求时将 header 对象塞到请求头部 uni.request({ url: https://www.example.com/request, // 仅为示例并非真实接口地址。 header: header, success: (res) { console.log(res.data); } });只要按照上述方式将 Token 值传递到后端Sa-Token 就能像传统 PC 端一样自动读取到 Token 值正常完成鉴权。你可能会问难道每个 ajax 都要写这么一坨岂不是麻烦死了——当然不能每个 ajax 都写一遍这种重复性代码应当封装在一个统一的请求函数里例如封装request(options)工具函数在函数内部统一注入 header业务页面只关心业务参数即可。四、后端如何读取前端提交的 Token源码级解读前端提交 Token 后Sa-Token 是怎么把它找出来的这决定了前端的提交方式必须与后端的读取逻辑严格对齐。4.1 Token 的读取顺序从源码 StpLogic.java 的getTokenValueNotCut()方法可以看到后端读取 Token 时按以下顺序依次尝试先尝试从 Storage 存储器里读取即本次请求中登录动作刚刚创建、暂存在请求级缓存里的 Token解决登录接口立即取 Token的场景再尝试从请求体 / URL 参数里读取当配置项isReadBody开启时调用request.getParam(tokenName)从 Query 参数与表单体读取例如GET /user/getInfo?satokenxxx再尝试从 Header 头里读取当配置项isReadHeader开启时调用request.getHeader(tokenName)读取即本文第三章前端所采用的方式最后尝试从 Cookie 里读取当配置项isReadCookie开启时调用request.getCookieValue(tokenName)读取兼容传统 PC 端场景。只要在前面的步骤中读到了值就不再继续向后尝试。官方示例 LoginAuthController.java 中的注释也印证了这一读取顺序Query 参数 → Header 头 → Cookie且明确说明以上三个地方都读取不到 Token 信息的话则视为前端没有提交 Token。4.2 关键配置项上述读取行为由全局配置控制配置项定义于 SaTokenConfig.java配置项默认值含义token-namesatokenToken 名称同时也是 Cookie 名称、提交 Token 时参数的名称、存储 Token 时的 key 前缀is-read-bodytrue是否尝试从请求体里读取 Tokenis-read-headertrue是否尝试从 header 里读取 Tokenis-read-cookietrue是否尝试从 cookie 里读取 Token因此前端 Header 中的参数名必须与token-name保持一致默认satoken后端才能读得到。这也是第三章方式二比方式一更推荐的原因它从后端返回的tokenName动态取值后端一旦修改token-name配置前端无需改动代码。4.3 响应头方式另一种后端下发的变体除了登录接口返回SaTokenInfo这种最常见的下发方式源码还提供了setTokenValueToResponseHeader()方法见 StpLogic.java登录后将 Token 写入当前请求的响应头中同时会自动添加Access-Control-Expose-Headers: tokenName响应头否则跨域场景下前端 JS 无法读取到该自定义响应头。这种方式适合登录接口不方便改返回结构、希望通过响应头透传 Token 的团队可结合项目实际情况选用。五、其它解决方案手动模拟 Cookie如果你对 Cookie 非常了解就会明白一个本质所谓 Cookie本质上就是一个特殊的 Header 参数而已即Cookie: namevalue。既然它只是一个 Header 参数我们就能手动模拟实现它前端自行维护一个类 Cookie机制如把 Token 存入本地存储并在每次请求时以Cookie头或自定义头的方式带上从而在不依赖浏览器 Cookie 的前提下完成鉴权闭环。这其实是无 Cookie 模式的另一种通用解法其思路与第三章的 Header 提交方案殊途同归感兴趣的同学可以进一步研究 Cookie 的规范细节在此不再赘述。六、小结与更多延伸至此无 Cookie 模式下的完整闭环已经清晰下发登录后调用StpUtil.getTokenInfo()把tokenNametokenValue返回给前端保存存储前端将这两个值存入本地存储如 uni-app 的setStorageSync提交前端在统一请求封装中将{tokenName: tokenValue}塞入请求 Header读取Sa-Token 按 Storage → 请求体/Query → Header → Cookie 的顺序自动识别前端提交的 Token完成鉴权。在此基础上还可以继续探索更进阶的配套能力均为本仓库内官方文档登录认证详解StpUtil.login()的完整登录流程与多账号体系框架配置token-name、is-read-header等全部配置项说明Token 前缀如Bearer等前缀模式下前后端如何正确提交与裁剪 TokenNotCookieController.java 完整示例可直接运行的前后端分离登录样例运行后可访问http://localhost:8081/NotCookie/doLogin2?namezhangpwd123456观察返回的SaTokenInfo结构。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考