模式:原理、实现与前后端分离方案)
Sa-Token 记住我Remember Me模式原理、实现与前后端分离方案【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token本文围绕 Sa-Token 的“[记住我] 模式”展开讲解其背后的 Cookie 生命周期原理、StpUtil.login()的完整参数体系以及 APP、小程序、PC 前后端分离环境下的等价实现方案。读完本文你将掌握如何用一行代码控制登录后的浏览器会话存留并为不同客户端定制 Token 有效期、持久 Cookie 与响应头写入等细节行为。什么是 [记住我] 模式大多数网站的登录界面都会提供一个[记住我]复选框勾选它登录后即使关闭浏览器再重新打开网站用户依然处于登录状态无须重新输入密码不勾选时一旦关闭浏览器会话即随之失效。其本质是浏览器Cookie 生命周期的两种形态临时 Cookie有效期仅限本次会话浏览器进程关闭浏览器窗口即被清除持久 Cookie有效期是一个具体的时间段只要未到期即使关闭浏览器 Cookie 也依然保留。Sa-Token 正是利用这一特性把 Token 的存留策略与“是否记住我”绑定勾选时写入持久 Cookie不勾选时写入临时 Cookie。在 Sa-Token 中实现默认就是 [记住我]Sa-Token 的登录授权默认就是[记住我]模式。因此如果要实现“非记住我”关闭浏览器后需重新登录只需要在登录时显式传入false// 设置登录账号id为10001第二个参数指定是否为[记住我] // 当此值为 false 后关闭浏览器再次打开需要重新登录 StpUtil.login(10001, false);该重载在 StpUtil.java 中定义isLastingCookie为true时即“记住我”false时关闭浏览器需重新登录。从源码可以推断它最终等价于StpUtil.login(10001, new SaLoginParameter().setIsLastingCookie(false));仓库内 sa-token-demo-case 提供了可直接运行对照的示例接口// 记住我登录 ---- http://localhost:8081/RememberMe/doLogin?namezhangpwd123456 StpUtil.login(10001, true); // 不记住我登录 ---- http://localhost:8081/RememberMe/doLogin2?namezhangpwd123456 StpUtil.login(10001, false);实现原理Token 写入 Cookie 的底层机制登录后Sa-Token 会把 Token 写入当前会话的 Cookie核心逻辑位于 StpLogic.java 的setTokenValueToCookie()方法SaCookie cookie new SaCookie() .setName(getTokenName()) .setValue(tokenValue) .setMaxAge(cookieTimeout) // Cookie 存活时间单位秒 ... SaHolder.getResponse().addCookie(cookie);关键在于cookieTimeout的取值它由 SaLoginParameter.getCookieTimeout() 计算得出public int getCookieTimeout() { if (!Boolean.TRUE.equals(getIsLastingCookie())) { return -1; // 非持久 Cookie-1浏览器关闭即失效 } long _timeout getTimeout(); if (_timeout SaTokenDao.NEVER_EXPIRE || _timeout Integer.MAX_VALUE) { return Integer.MAX_VALUE; // 永不过期或超大值取 Integer 上限 } return (int)_timeout; // 持久 Cookie存活时间 Token 有效期 }于是两种模式在浏览器侧表现为登录方式写入的 CookieCookie Max-Age关闭浏览器后StpUtil.login(10001, true)持久 Cookie等于 Token 有效期秒Token 仍保留无需重新登录StpUtil.login(10001, false)临时 Cookie-1内存 CookieToken 随浏览器进程消失会话失效这也解释了为什么“不记住我”模式下服务端 Token 数据其实并未立即删除——只是浏览器丢失了 Token 凭据下次无法再携带它发起认证。全局配置isLastingCookie 默认值为 true“默认就是记住我”的根源在于全局配置。在 SaTokenConfig.java 中/** * 是否为持久Cookie临时Cookie在浏览器关闭时会自动删除持久Cookie在重新打开后依然存在 */ private Boolean isLastingCookie true;如果希望整个项目默认走“非记住我”可以在配置文件中将sa-token.is-lasting-cookie设为false随后未显式指定该参数的login()调用都会自动使用非持久 Cookie。前后端分离Cookie 失效了怎么办一个自然的疑问是Cookie 方案依赖浏览器会话机制那在APP、小程序等前后端分离环境下是否无效答案是肯定的——任何基于 Cookie 的认证方案在前后端分离环境下都会失效因为这些客户端默认没有实现 Cookie 功能。不过它们通常都提供了替代的本地存储机制代价是Token 的生命周期需要由前端手动控制。以经典跨端框架uni-app为例// 使用本地存储保存 token达到 [持久Cookie] 的效果 uni.setStorageSync(satoken, xxxx-xxxx-xxxx-xxxx-xxx); // 使用 globalData 保存 token达到 [临时Cookie] 的效果 getApp().globalData.satoken xxxx-xxxx-xxxx-xxxx-xxx;若在PC 浏览器环境下进行前后端分离开发则更加简单// 使用 localStorage 保存 token达到 [持久Cookie] 的效果 localStorage.setItem(satoken, xxxx-xxxx-xxxx-xxxx-xxx); // 使用 sessionStorage 保存 token达到 [临时Cookie] 的效果 sessionStorage.setItem(satoken, xxxx-xxxx-xxxx-xxxx-xxx);提示localStorage的数据不会随标签页/窗口关闭而清除对应“记住我”sessionStorage的生命周期与浏览器会话绑定对应“非记住我”。仓库中 sa-token-demo-remember-me 提供了一个完整的 Vue3 Vite 前端工程 Spring Boot 后端的“记住我”演示后端 UserLoginController.java 通过StpUtil.login(10001, remember)接收前端复选框状态前端工程在page_project/目录下可参考其登录、状态校验与注销的完整交互。登录时指定 Token 有效期“记住我”只是二选一的开关实践中往往还需要精确控制 Token 的有效时长。登录时可以用SaLoginParameter指定一个具体时间单位秒// 示例1指定 token 有效期单位秒如下所示 token 七天有效 StpUtil.login(10001, new SaLoginParameter().setTimeout(60 * 60 * 24 * 7));当传入timeout后持久 Cookie 的 Max-Age 也会同步等于该时长见上文getCookieTimeout()逻辑即“记住我 七天有效”。对应地StpUtil.login(Object id, long timeout)这个便捷重载可直接使用// 七天免登录 ---- http://localhost:8081/RememberMe/doLogin3?namezhangpwd123456 StpUtil.login(10001, 60 * 60 * 24 * 7);上述接口均可在 RememberMeController.java 中看到完整上下文。SaLoginParameter登录参数的完整清单SaLoginParameter是登录时的参数 Model除“记住我”与有效期外还决定登录过程中的各种行为。该类的全部字段与含义定义于 SaLoginParameter.java核心参数整理如下参数含义备注/默认来源deviceType此次登录的客户端设备类型用于[同端互斥登录]时指定设备端默认取全局配置deviceId此次登录的客户端设备 id用于设备维度会话管理timeout此次登录 token 有效期秒未指定时自动取全局timeout值activeTimeout此次登录 token 最低活跃频率秒未指定时使用全局activeTimeoutisConcurrent是否允许同一账号多地同时登录true一起登录false新登录挤掉旧登录isShare多人登录同一账号时是否共用一个 tokentrue共用false每次新建maxLoginCount同一账号最大登录数量-1不限仅在isConcurrenttrue, isSharefalse时有意义maxTryTimes创建 token 时的最高循环尝试次数用于保证 token 唯一性-1不循环直接使用isLastingCookie是否为持久 Cookietrue记住我false临时 CookieisWriteHeader是否在登录后将 Token 写入响应头前后端分离场景常用token预定本次登录生成的 Token 值需自行保证唯一性rightNowCreateTokenSession登录时是否立即创建 Token-Sessiontrue立即创建false首次调用getTokenSession()时创建replacedLoginExitMode/replacedRange顶人下线时的策略与范围仅isConcurrentfalse时生效overflowLogoutMode溢出maxLoginCount时的下线方式LOGOUT注销 /KICKOUT踢人 /REPLACED顶人extraData扩展信息只在 jwt 模式下生效cookieCookie 配置对象可单独覆盖 domain、path、secure、httpOnly、sameSite 等一个覆盖主要参数的完整示例StpUtil.login(10001, new SaLoginParameter() .setDeviceType(PC) // 此次登录的客户端设备类型用于[同端互斥登录]时指定此次登录的设备类型 .setIsLastingCookie(true) // 是否为持久Cookie临时Cookie在浏览器关闭时会自动删除持久Cookie在重新打开后依然存在 .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期单位:秒如未指定自动取全局配置的 timeout 值 .setToken(xxxx-xxxx-xxxx-xxxx) // 预定此次登录生成的Token .setIsWriteHeader(false) // 是否在登录后将 Token 写入到响应头 );从源码结构看SaLoginParameter的构造器会调用setDefaultValues(SaManager.getConfig())将全局配置一次性填充为默认值SaLoginParameter.java因此你只需显式设置需要覆盖的字段未指定的行为自动跟随全局配置这正是“按次登录精细控制、不污染全局”的设计思路。实践建议与注意事项区分两层过期服务端 Token 过期时间与浏览器 Cookie 存活时间并非同一概念。持久 Cookie 只是让 Token 凭据“不丢”真正限制登录状态的是 Token 有效期非持久 Cookie 则是“凭据丢失”导致被动下线。理解这一点有助于排查“明明没过期却掉线”的问题。前后端分离时前端负责“存”由于不依赖 CookieToken 的持久与否由前端存储方案localStorage / sessionStorage / 小程序本地存储决定服务端只需保证 Token 本身的有效期配置正确。响应头透传在 APP 等场景可将isWriteHeader设为true登录后从响应头读取 Token再由前端按需求自行存储这与 SaTokenConfig 中isReadHeader、isReadCookie的读写配置相互配合构成完整的双端 Token 传递闭环。安全提示为持久 Cookie 设置合理的有效期而非永不过期并配合 Token 活跃频率activeTimeout实现“长时间无操作自动失效”可在便利性与安全性之间取得平衡。至此从“勾选记住我”到“指定七天有效期”再到前后端分离环境下的存储策略Sa-Token 的会话存留机制已全部打通——正如官方文档所言Remember me, its too easy!【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考