尧图精选

Sa-Token 踢人下线详解:强制注销、踢人下线与顶人下线的原理与实践

🕒 发布时间:2026/9/13 14:13:25 📁 来源:尧图网络
Sa-Token 踢人下线详解强制注销、踢人下线与顶人下线的原理与实践【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-TokenSa-Token 是开源、免费的 Java 权限认证框架其踢人下线能力用于后台治理会话管理员或业务代码可以按账号、按设备端、按 Token 值将指定用户的会话强制注销或踢下线。本文以 官方文档 为骨架结合 StpLogic 核心实现 与 Demo 示例讲清楚三种下线方式的 API 用法、场景值差异与底层调用链读完你可以直接在业务代码中实现后台踢人按端注销新登录顶掉旧设备等常见会话治理功能。一、什么是踢人下线所谓踢人下线核心操作就是找到指定loginId对应的Token并设置其失效。在 Sa-Token 的数据模型中框架会在持久层SaTokenDao维护一张token-value - loginId的映射表会话是否有效取决于这张映射表里的数据。因此无论按账号踢、按设备端踢还是按 Token 踢最终落点都是清理或篡改这条映射记录清理映射删除token-value - loginId记录对应强制注销篡改映射把token-value - loginId更新为一个特殊标记值对应踢人下线 / 顶人下线。映射的写入、更新、删除分别由 saveTokenToIdMapping / updateTokenToIdMapping / deleteTokenToIdMapping 完成它们最终都委托给SaTokenDao默认内存实现可切换 Redis 等分布式存储这就是三种下线方式共用的一套底层机制。二、强制注销logout强制注销的语义是等价于对方主动调用了注销方法让指定账号的会话立即失效。2.1 三个核心 APIStpUtil.logout(10001); // 强制指定账号注销下线 StpUtil.logout(10001, PC); // 强制指定账号指定端注销下线 StpUtil.logoutByTokenValue(token); // 强制指定 Token 注销下线三个方法的含义API作用定位粒度StpUtil.logout(loginId)强制指定账号注销下线账号所有设备端StpUtil.logout(loginId, deviceType)强制指定账号指定端注销下线账号 设备端StpUtil.logoutByTokenValue(tokenValue)强制指定 Token 注销下线单条 Token其中deviceType参数如PC、APP、H5是登录时通过StpUtil.login(loginId, deviceType)指定的设备类型标记。从 StpLogic.logout(loginId, deviceType) 的源码注释可以看出deviceType填null代表注销该账号的所有设备类型。2.2 注销后的行为强制注销会彻底清除 Token 信息包括 Token 映射、Token-Session 等对方再次访问系统时会抛出NotLoginException异常提示语为token 无效。三、踢人下线kickout踢人下线是后台管理最常用的操作管理员可以随时把某个可疑账号或某台设备踢下线而不需要破坏它已经产生的数据。3.1 三个核心 APIStpUtil.kickout(10001); // 将指定账号踢下线 StpUtil.kickout(10001, PC); // 将指定账号指定端踢下线 StpUtil.kickoutByTokenValue(token); // 将指定 Token 踢下线用法与logout系列完全对应API作用定位粒度StpUtil.kickout(loginId)将指定账号踢下线账号所有设备端StpUtil.kickout(loginId, deviceType)将指定账号指定端踢下线账号 设备端StpUtil.kickoutByTokenValue(tokenValue)将指定 Token 踢下线单条 Token同样deviceType填null代表踢出该账号的所有设备类型见 StpLogic.kickout(loginId, deviceType)。3.2 强制注销 vs 踢人下线的区别这是本主题最核心的辨析点强制注销等价于对方主动调用了注销方法Token 映射被彻底删除对方再次访问会提示Token 无效踢人下线不会清除 Token 信息而是将其打上特定标记对方再次访问会提示Token 已被踢下线。打上特定标记在源码中体现得很直观。在 StpLogic._fireLogoutEvent 中// SaLogoutMode.LOGOUT注销下线 —— 真正删除映射 deleteTokenToIdMapping(tokenValue); SaTokenEventCenter.doLogout(loginType, loginId, tokenValue); // SaLogoutMode.KICKOUT踢人下线 —— 把映射更新为特殊标记 updateTokenToIdMapping(tokenValue, NotLoginException.KICK_OUT); SaTokenEventCenter.doKickout(loginType, loginId, tokenValue);其中NotLoginException.KICK_OUT的值是字符串-5定义于 NotLoginException/** 表示 token 已被踢下线 */ public static final String KICK_OUT -5; public static final String KICK_OUT_MESSAGE token 已被踢下线;也就是说踢人下线后DAO 中原本token - 10001的映射变成了token - -5。下次该 Token 再访问时框架取出的 loginId 是-5被判定为被踢下线并抛出NotLoginException场景值type -5。由于 Token 记录本身还保留在存储中其 Token-Session 等关联数据也更便于后续排查或恢复。四、顶人下线replaced顶人下线操作发生在框架登录时顶退旧登录设备属于框架内部操作一般情形下你不会调用到此 APIStpUtil.replaced(10001); // 将指定账号顶下线 StpUtil.replaced(10001, PC); // 将指定账号指定端顶下线 StpUtil.replacedByTokenValue(token); // 将指定 Token 顶下线它与踢人下线的差异点触发场景不同replaced通常在同账号新设备登录、旧设备被顶退的互斥登录场景中被框架内部调用配合isConcurrent、maxLoginCount等配置业务代码一般用不到场景值不同顶人下线写入的标记是NotLoginException.BE_REPLACED -4源码定义对方再次访问会提示token 已被顶下线保留 Account-Session从 StpLogic._logout 的注释可以看到调用顶替下线时通常新客户端正在登录因此不会注销该账号的 Account-Session避免注销后又立刻创建造成不必要的性能浪费而注销/踢人下线后若账号已无任何在线终端会通过session.logoutByTerminalCountToZero()将 Account-Session 一并注销。五、三种下线方式对比速查表对比项强制注销 logout踢人下线 kickout顶人下线 replaced典型使用方用户主动退出 / 后台强退后台管理踢出可疑会话框架登录时顶退旧设备对 Token 映射的处理删除映射更新为-5标记更新为-4标记对方再次访问的提示token 无效token 已被踢下线token 已被顶下线NotLoginException 场景值-2INVALID_TOKEN-5KICK_OUT-4BE_REPLACED是否保留 Account-Session终端清零时注销终端清零时注销保留新客户端在登录框架事件回调doLogout / doBeforeLogoutdoKickout / doBeforeKickoutdoReplaced / doBeforeReplaced场景值常量统一收敛在 NotLoginException.ABNORMAL_LIST-1 ~ -7业务代码可用e.getType()精确判断会话失效原因进而区分提示语或跳转逻辑。六、底层原理一条 Token 下线要经历什么三种方式最终都汇入StpLogic._logoutByTokenValue(tokenValue, logoutParameter)源码logoutParameter中的modeSaLogoutMode.LOGOUT / KICKOUT / REPLACED见 SaLogoutMode 枚举决定了后续走删除还是打标记。完整调用链如下前置校验根据 token 解析 loginIdgetLoginIdByTokenNotThinkFreeze若 loginId 为空则直接返回避免写入意外数据同时检查isFreeze冻结状态发布注销前事件_fireBeforeLogoutEvent按 mode 触发doBeforeLogout/doBeforeKickout/doBeforeReplaced源码可用于在会话失效前做审计、通知等清理最后活跃时间开启活跃度校验isOpenCheckActiveTimeout时调用clearLastActive清理 Token-Session未开启isKeepTokenSession时调用deleteTokenSession处理 Token 映射并发布事件_fireLogoutEvent中按 mode 删除或篡改映射并触发doLogout/doKickout/doReplaced源码清理终端信息从 Account-Session 移除该 Token 对应的SaTerminalInfo若终端数为 0 则尝试注销 Account-Session。而按loginId下线的_logout(loginId, logoutParameter)源码则先取出该账号的 Account-Session遍历其终端列表按deviceType、deviceId过滤后对每个命中的终端逐一执行_removeTerminal最终走一遍上述清理 → 改映射 → 发事件的流程。这就是StpUtil.kickout(10001, PC)只影响 PC 端、不影响 APP 端的原理所在。另外框架的门面类 StpUtil 只是把上述方法逐一定向委托给内部stpLogicStpUtil.logout(...)转发到stpLogic.logout(...)等真实的业务逻辑全部封装在StpLogic这也意味着多账号体系下你可以为不同loginType创建独立的StpLogic实例实现分账号类型的精准踢人。七、实战示例后台踢人接口官方在 KickoutController.java 中提供了可直接运行的演示代码所在模块 sa-token-demo-case启动后访问http://localhost:8081RestController RequestMapping(/kickout/) public class KickoutController { // 将指定账号强制注销 ---- http://localhost:8081/kickout/logout?userId10001 RequestMapping(logout) public SaResult logout(long userId) { // 强制注销等价于对方主动调用了注销方法再次访问会提示Token无效。 StpUtil.logout(userId); return SaResult.ok(); } // 将指定账号踢下线 ---- http://localhost:8081/kickout/kickout?userId10001 RequestMapping(kickout) public SaResult kickout(long userId) { // 踢人下线不会清除Token信息而是将其打上特定标记再次访问会提示Token已被踢下线。 StpUtil.kickout(userId); return SaResult.ok(); } // 根据 Token 值踢人 ---- http://localhost:8081/kickout/kickoutByTokenValue?tokenValue已登录账号的token值 RequestMapping(kickoutByTokenValue) public SaResult kickoutByTokenValue(String tokenValue) { StpUtil.kickoutByTokenValue(tokenValue); return SaResult.ok(); } }操作步骤先调用登录接口登录一个账号http://localhost:8081/acc/doLogin?namezhangpwd123456分别访问上面的logout/kickout接口再访问登录校验接口http://localhost:8081/acc/checkLogin对比两次返回的提示信息差异——强制注销后报Token 无效踢人下线后报Token 已被踢下线直观验证两种方式的区别若想按 Token 精确踢人可从登录响应中拿到 token 值再调用kickoutByTokenValue。该行为同样有单元测试兜底在 StpLogicLogoutTest 中kickoutByTokenValue_marksTokenAsKicked验证了kickoutByTokenValue 后再次 checkLogin 应抛出 NotLoginExceptionlogoutByLoginId_clearsAccountSession验证了按 loginId 注销会清空 Token 映射与 Account-Session可作为理解框架行为的参考依据。八、进阶通过注销参数精细控制除上述基础 API 外所有下线方法都支持传入SaLogoutParameter做精细控制对应StpUtil.logout(loginId, SaLogoutParameter)、StpUtil.kickout(loginId, SaLogoutParameter)等重载。常用参数项定义见 SaLogoutParameter参数说明setDeviceType(String)仅注销/踢出指定设备端null 代表全部setDeviceId(String)仅注销/踢出指定设备 ID更细粒度的设备定位setRange(SaLogoutRange)注销范围TOKEN仅处理当前 TokenACCOUNT级联处理账号下全部终端setMode(SaLogoutMode)注销模式LOGOUT/KICKOUT/REPLACEDsetIsKeepTokenSession(boolean)是否保留 Token-Session 数据setIsKeepFreezeOps(boolean)遇到冻结 Token 时是否跳过处理例如只踢掉某账号在APP端且指定deviceId的会话可组合deviceType与deviceId两个条件实现比按端踢人更精准的单设备下线。九、关联文档与进一步阅读本文主题文档踢人下线kick.md登录认证与会话体系login-auth.md、session.md会话治理扩展search-session.md后台查询/管理会话、mutex-login.md互斥登录、单端登录全局事件监听doKickout / doReplaced 等回调的落地方式global-listener.md综上所述Sa-Token 的踢人下线能力虽然 API 只有几行背后却是一套账号 → 终端 → Token 映射的完整会话治理模型。理解deleteTokenToIdMapping与updateTokenToIdMapping的分野就能准确判断注销 / 踢下线 / 顶下线三种行为对既有会话数据的不同影响进而在后台管理中做到按需、按端、按 Token 的精细化下线控制。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →