SpringBoot3+OAuth2 企业 SSO:不透明 Token、Redis 热缓存与授权码一次性消费
SpringBoot3OAuth2 企业 SSO不透明 Token、Redis 热缓存与授权码一次性消费文档地址https://ruoyioffice.com源码1·GitHubhttps://github.com/yuqing2026/ruoyi-office源码2·GitCodehttps://gitcode.com/zhouzhongyan/ruoyi-office源码3·Giteehttps://gitee.com/yqzy1688/ruoyi-office微信17156169080备注「RuoYi Office」OA、CRM、报表、大屏一旦拆成多套入口员工就会同时记四套密码离职账号也清不干净。单点登录要的不是“少输一次密码”而是登录态可颁发、可续期、可审计、可立刻作废。本文按 RuoYi Office 的 OAuth2 实现讲清为什么 Access Token 用 UUID 而不是 JWT以及授权码、Redis 热缓存、令牌管理页如何咬合。▲ 客户端契约 → 一次性 code → UUID 双令牌双存储 → 续期作废旧票 / 管理端踢人引言SSO 难的是“登录态怎么管”纯 JWT 很香网关不用查库水平扩展简单。企业场景却会立刻碰到现状后果Token 自包含、改了角色还有效权限变更要等过期安全窗口不可控只把登录态放 RedisRedis 抖动或重启全员掉线只把登录态放 MySQL每个接口验票都打库第三方 302 重定向Axios 前端接不住授权页卡死报表 / WebSocket 只能带一个 token不会 refresh 就频繁 401RuoYi Office 的选择是OAuth2 协议语义 不透明 TokenUUID MySQL 持久化 Redis 热路径。JWT 可以以后作为某种 client 的可选项但默认管理端登录态必须能踢人。一、先登记客户端再谈发 Token每个接入系统是一行 OAuth2 Client编号、密钥、回调 URI、授权模式、Access / Refresh 有效期、scope。这些是契约不是注释。▲ 效果创建客户端时同时登记授权类型、Access/Refresh 秒数、可重定向 URI 和授权范围避免把密钥写死在业务代码里常见模式在字典里就有authorization_code、password、refresh_token、client_credentials、implicit。管理后台自己登录多用密码模式跨系统 SSO 必须走授权码。validOAuthClientFromCache会校验client 存在且启用本次 grantType 在允许列表中redirectUri 命中白名单申请的 scope 是子集。任何一项失败都不应发码更不应发 Token。二、授权码五分钟、一次性、三角校验2.1 同意授权页前后端分离后浏览器不会像传统 Servlet 那样吃 302。前端先拉客户端信息再POST /system/oauth2/authorize后端返回最终跳转 URL 字符串由location.href完成。▲ 效果已登录用户进入 SSO 页勾选「访问你的个人信息」后点同意若该 client 配置了自动授权范围可跳过这屏自动授权和手动授权是两条路径auto_approvetrue检查历史同意记录或 client 自动 scope通不过就返回空 URL前端停在同意页auto_approvefalse用户点同意/拒绝写入批准记录后再发码。2.2 发码与消费授权码默认5 分钟生成同样用 UUIDpublicOAuth2CodeDOconsumeAuthorizationCode(Stringcode){OAuth2CodeDOcodeDOoauth2CodeMapper.selectByCode(code);if(codeDOnull){throwexception(OAUTH2_CODE_NOT_EXISTS);}if(DateUtils.isExpired(codeDO.getExpiresTime())){throwexception(OAUTH2_CODE_EXPIRE);}oauth2CodeMapper.deleteById(codeDO.getId());// 一次性returncodeDO;}换票时还要核对clientId、redirectUri、state。这三项有一项对不上就说明回调被劫持或客户端配错了必须拒绝。code 用过即删重放无效。三、不透明 Token可撤销比自包含更重要3.1 颁发Access 和 Refresh 都是IdUtil.fastSimpleUUID()有效期来自 client 配置演示环境常见 Access 1800 秒。Access 写入 MySQL 后立刻写入 RedisRefresh 以 MySQL 为准。privateOAuth2AccessTokenDOcreateOAuth2AccessToken(OAuth2RefreshTokenDOrefreshTokenDO,OAuth2ClientDOclientDO){OAuth2AccessTokenDOtokennewOAuth2AccessTokenDO().setAccessToken(generateAccessToken()).setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()).setUserInfo(buildUserInfo(refreshTokenDO.getUserId(),refreshTokenDO.getUserType())).setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes()).setRefreshToken(refreshTokenDO.getRefreshToken()).setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds()));oauth2AccessTokenMapper.insert(token);oauth2AccessTokenRedisDAO.set(token);returntoken;}userInfo在颁发时写入昵称和部门避免每个请求再打用户表。租户号优先取 Refresh 上的tenantId防止 ThreadLocal 被污染写成 null。3.2 验票Redis 未命中再回源publicOAuth2AccessTokenDOgetAccessToken(StringaccessToken){OAuth2AccessTokenDOtokenoauth2AccessTokenRedisDAO.get(accessToken);if(token!null){returntoken;}tokenoauth2AccessTokenMapper.selectByAccessToken(accessToken);if(tokennull){// 报表 / WebSocket 只能带一个串时允许用未过期的 Refresh 顶一下OAuth2RefreshTokenDOrefreshoauth2RefreshTokenMapper.selectByRefreshToken(accessToken);if(refresh!null!DateUtils.isExpired(refresh.getExpiresTime())){tokenconvertToAccessToken(refresh);}}if(token!null!DateUtils.isExpired(token.getExpiresTime())){oauth2AccessTokenRedisDAO.set(token);}returntoken;}这是刻意的兼容不是协议纯洁主义。积木报表、WebSocket URL 往往塞不下 refresh_token若死守“只能用 Access”业务会逼着把 Access 有效期拉到几天安全更差。Redis 写入时 TTL 剩余秒数并清掉 creator/updateTime 等审计字段避免缓存体膨胀。过期 key 自动消失与 MySQL 过期判断双保险。3.3 续期会作废旧 AccessrefreshAccessToken先按 refresh 查出所有 AccessMySQL 和 Redis 一起删再发新 Access。Refresh 过期则连 Refresh 行也删返回未授权。这样“续期”不会在库里堆出一串仍有效的旧票。踢人更直接令牌管理页删除一行调用removeAccessTokenAccess Refresh Redis 同步清理。按用户维度的强制下线则遍历该用户全部 Access 做同样的事。▲ 效果访问令牌是 32 位 UUID 而不是三段式 JWT删除即踢当前会话不必等 30 分钟自然过期过期清理是分批deleteLimit循环避免大表一次性锁死。Access 和 Refresh 各有清理入口留给定时任务而不是靠用户撞 401。四、授权模式怎么分工模式谁用风险点authorization_code第三方系统 SSOredirectUri 必须白名单code 必须一次性password管理端自身登录只给第一方第三方禁止用refresh_token所有需要静默续期的端必须校验 clientId 与原票一致client_credentials服务间调用用户 ID 为 0必须限制 scopeimplicit历史兼容前端直接拿 Token默认不建议新系统启用密码模式走authenticate(username, password)再createAccessToken。它不是 SSO 的主路径只是第一方登录的 OAuth2 外壳方便和第三方共用同一套 Token 存储。五、和 JWT 的边界不要做成宗教讨论维度不透明 UUID自包含 JWT踢人删库 删缓存立刻失效除非黑名单否则等过期改角色下次验票读库/缓存里的新信息旧 Token 仍带旧角色声明网关压力要查 Redis只验签Token 体积短声明一多就变长离线校验不行可以企业后台、审批、财务对“立刻踢人”的需求强于“网关零查询”。报表大屏若必须离线验签可以给那个 client 单独发 JWT不必把管理端默认登录态也改掉。六、前端对应关系页面作用/system/oauth2/oauth2/application登记 client 契约/system/oauth2/token审计当前票、踢人/auth/sso-login第三方授权同意页SSO 页会先尝试自动授权URL 上带了scope且历史已同意就直接跳转用户甚至看不到同意屏。这是体验优化前提是自动 scope 必须在 client 上显式配置不能默认全开。七、数据结构精简客户端表client_id、secret、redirect_uris、authorized_grant_types、scopes、access_token_validity_seconds、refresh_token_validity_seconds。Access 表access_token、refresh_token、user_id、user_type、client_id、scopes、expires_time、user_info、tenant_id。Refresh 表字段与 Access 类似有效期更长。授权码表code、redirect_uri、state、五分钟过期消费后物理删除。Redis key 按 Access 字符串格式化TTL 对齐剩余寿命。八、技术亮点设计要点实现方式价值不透明 TokenUUID不自包含可立刻撤销双存储MySQL 权威 Redis 热路径可审计、扛 QPSRedis TTL剩余秒数过期自然淘汰授权码一次性消费即删防重放三角校验client / redirect / state防回调劫持续期作废旧票按 refresh 删全部 Access不堆积有效会话特殊通道兼容未过期 Refresh 可当 Access 验报表 / WS 能用前端拿 URL不依赖 Axios 302分离架构可落地九、快速体验在线演示https://ruoyioffice.com/web/账号 admin / admin123推荐路径系统管理 → OAuth 2.0 → 应用管理打开新增表单看授权类型和回调 URI进入令牌管理确认 Access 是 UUID删除一条观察是否立即需要重新登录用带client_id、redirect_uri、response_typecode的地址打开 SSO 授权页同意后看回调 URL 上的code重复使用应失败。源码仓库GitHubhttps://github.com/yuqing2026/ruoyi-officeGitCodehttps://gitcode.com/zhouzhongyan/ruoyi-officeGiteehttps://gitee.com/yqzy1688/ruoyi-office常见问题FAQ为什么默认不用 JWT管理端要支持改权限立即生效、离职立即踢人。JWT 做不到这一点除非再维护黑名单那已经失去“无状态”的优点。Access 只有 30 分钟会不会总掉线前端用 Refresh 静默续期。续期会作废旧 Access所以同时只应保留当前这一张热票。密码模式给第三方用可以吗不可以。密码模式等于把账号密码交给对方。第三方只走授权码 回调白名单。Redis 挂了会不会全员登出不会立刻。验票会回源 MySQL 并回填 Redis。Redis 只是加速层权威在数据库。为什么授权接口返回 URL 而不是 302浏览器 Axios 默认不把跨域 302 当授权完成处理。返回字符串后由前端跳转行为可预期也方便带上已登录态 Cookie/Token。结语企业 SSO 的目标不是“少输一次密码”而是把登录态变成可治理的资源谁发的、发给哪个 client、何时过期、能否续、能否立刻作废。不透明 Token 加双存储看起来比 JWT 多一次查询却换来权限变更和人员离职时真正可用的控制面。想要体验 RuoYi Office 的强大功能在线演示https://ruoyioffice.com/web/账号 admin / admin123源码仓库GitHubhttps://github.com/yuqing2026/ruoyi-office GitCodehttps://gitcode.com/zhouzhongyan/ruoyi-office Giteehttps://gitee.com/yqzy1688/ruoyi-office技术咨询添加微信17156169080备注「RuoYi Office」⭐如果觉得不错请给个 Star 支持一下

相关新闻

网站被攻击怎么办?站长必备的应急响应指南

网站被攻击怎么办?站长必备的应急响应指南

网站被攻击怎么办?站长必备的应急响应指南导读 在数字化时代,网站已成为企业展示形象、开展业务的重要平台。然而,随着网络攻击手段的不断升级,网站安全威胁日益严峻。从DDoS攻击、SQL注入到XSS跨站脚本,各类安全漏洞可…

2026/8/23 23:06:29 阅读更多 →
关于文件系统和文件格式

关于文件系统和文件格式

关于文件系统和文件格式现在电脑启动都是uefigptgpt分区表记录了硬盘上每个分区的信息,比如每个分区从哪个扇区开始,每个分区分了多少个最前面的扇区来存储系统盘里面的启动程序,在启动程序后面的扇区分了多少个扇区存储文件格式数据&#xf…

2026/8/23 23:06:29 阅读更多 →
AI工具普及后,程序员还能靠什么拿到offer?

AI工具普及后,程序员还能靠什么拿到offer?

如果你正准备往大模型方向转,《一份看似完整的程序员就业方案,为什么投递时没效果?》这类问题别只看热度。更重要的是判断自己该补哪块能力,以及怎么证明你真的会。摘要摘要:2026年AI编程工具已进入团队协作阶段&#…

2026/8/23 23:06:29 阅读更多 →

最新新闻

论文AI率过高怎么办?2026年12款免费降AI率工具实测指南

论文AI率过高怎么办?2026年12款免费降AI率工具实测指南

现在毕业论文答辩前,“AI率超标”已经彻底取代“查重率过高”,成了同学们的头号难题!不少同学只是用AI润色了摘要和结论,AI率直接飙升到离谱,纯手动修改根本不管用——这说明AIGC检测系统抓的不是个别词语,…

2026/8/23 23:59:54 阅读更多 →
Marketch:从Sketch画板直接量取CSS

Marketch:从Sketch画板直接量取CSS

Marketch:从Sketch画板直接量取CSS 【免费下载链接】marketch Marketch is a Sketch 3 plug-in for automatically generating html page that can measure and get CSS styles on it. 项目地址: https://gitcode.com/gh_mirrors/ma/marketch 设计稿交付还在…

2026/8/23 23:59:54 阅读更多 →
如何在ThinkPad X390上安装macOS:OpenCore EFI完整指南

如何在ThinkPad X390上安装macOS:OpenCore EFI完整指南

如何在ThinkPad X390上安装macOS:OpenCore EFI完整指南 【免费下载链接】ThinkpadX390-Opencore-EFI macOS Catalina & Big Sur & Monterey on ThinkPad X390 (Hackintosh) 项目地址: https://gitcode.com/gh_mirrors/th/ThinkpadX390-Opencore-EFI …

2026/8/23 23:59:54 阅读更多 →
WechatHook 终极指南:5大核心能力详解,3分钟看懂微信自动化

WechatHook 终极指南:5大核心能力详解,3分钟看懂微信自动化

WechatHook 终极指南:5大核心能力详解,3分钟看懂微信自动化 【免费下载链接】WechatHook Enjoy hooking wechat by Xposed....Accessibility...and so on... 项目地址: https://gitcode.com/gh_mirrors/we/WechatHook WechatHook 是一个基于 Xpos…

2026/8/23 23:59:54 阅读更多 →
OpenModScan:免费跨平台 Modbus 主站调试工具,让现场通讯验证一键搞定

OpenModScan:免费跨平台 Modbus 主站调试工具,让现场通讯验证一键搞定

OpenModScan:免费跨平台 Modbus 主站调试工具,让现场通讯验证一键搞定 【免费下载链接】OpenModScan Open ModScan is a Free Modbus Master (Client) Utility 项目地址: https://gitcode.com/gh_mirrors/op/OpenModScan OpenModScan 是一款开源免…

2026/8/23 23:59:54 阅读更多 →
Gin-JWT认证与授权方案从Token到RBAC权限控制

Gin-JWT认证与授权方案从Token到RBAC权限控制

Gin-JWT认证与授权方案从Token到RBAC权限控制 文章导语 JWT(JSON Web Token)是现代Web服务的身份认证标准。在Gin框架中集成JWT看似简单,但涉及Token刷新、黑名单、多设备登录、RBAC权限控制等实际需求时,就需要更完善的设计。本文…

2026/8/23 23:57:54 阅读更多 →

日新闻

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/23 18:47:06 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/23 12:10:44 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →