ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Sa-Token SSO 平台中心跳转模式:把 sso-server 建成统一门户,一次登录免登进入全部子系统

Sa-Token SSO 平台中心跳转模式:把 sso-server 建成统一门户,一次登录免登进入全部子系统 Sa-Token SSO 平台中心跳转模式把 sso-server 建成统一门户一次登录免登进入全部子系统【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token本篇围绕 Sa-Token SSO 的“平台中心跳转模式”展开当 sso-server 不再只是认证中心而是承担企业门户首页的角色时如何做到“平台中心一处登录所有子系统无障碍通行”。文中给出完整的home-route配置、平台首页 Controller 代码并结合 sa-token-sso 模块源码解析跳转链接背后的 ticket 免登录机制读完你可以独立搭建一套“登录中心 子系统导航首页”的 SSO 门户。一、场景说明sso-server 即平台中心在标准 SSO 场景下sso-server 通常只做一件事提供登录页并在认证成功后重定向回发起请求的子系统。但在很多多业务线、多子系统并存的企业环境中运营方希望把 sso-server 搭建成一个平台中心统一门户用户访问平台地址如http://sa-sso-server.com:9000未登录则先进入/sso/auth登录页登录成功后回到平台首页首页上罗列各子系统的进入链接用户点击某个子系统链接浏览器直接跳转到该子系统并且跳转的同时自动完成子系统登录无需再次输入账号密码。难点不在“加超链接”这毫无技术含量而在于第 3 步如何让一次普通的链接跳转触发子系统的自动登录。直接跳转肯定做不到需要对跳转链接做协议化改造。二、核心原理对跳转链接做一次“SSO 协议化”改造假设某子系统的地址是http://sa-sso-client1.com:9003/将其改造为平台首页上可点击的链接/sso/auth?clientsso-client3redirecthttp://sa-sso-client1.com:9003/sso/login?backhttp://sa-sso-client1.com:9003/通用格式形如/sso/auth?client{client标识}redirect${子系统首页}/sso/login?back${子系统首页}这个格式的含义需要拆开理解链接首先指向 sso-server 的/sso/auth授权入口redirect参数并不直接指向子系统首页而是指向子系统的 SSO 登录中转页/sso/loginback参数内嵌在 redirect 里才是子系统真正的落地地址。也就是说用户点击链接后的完整路径是平台首页 → sso-server/sso/auth→ 子系统/sso/login?ticketxxxbackxxx→ 子系统首页。真正完成“免登录”动作的是子系统/sso/login中转页这一点下文的源码分析会详细展开。三、第一步在 sso-server 配置home-routehome-route解决的是登录完成后的“落点”问题用户在/sso/auth登录页完成认证、但请求中没有指定redirect参数即用户不是从某个子系统跳来的而是直接访问认证中心时认证中心应该把用户送到哪里。此时就重定向到home-route配置的路由上也就是平台首页。yaml 风格配置# Sa-Token 配置 sa-token: # SSO-Server 配置 sso-server: # 主页路由在 /sso/auth 登录页不指定 redirect 参数时默认跳转的地址 home-route: /homeproperties 风格配置# 主页路由在 /sso/auth 登录页不指定 redirect 参数时默认跳转的地址 sa-token.sso-server.home-route: /home该配置项映射到 SaSsoServerConfig 配置类的homeRoute字段无默认值需显式配置。其消费逻辑位于 SaSsoServerProcessor.ssoAuth()// 若 redirect 参数为空说明用户并不是从 client 重定向来的而是直接访问的 http://sso-server.com/sso/auth 地址 // 此时需要跳转到配置的 homeRoute 路由上 // 若 homeRoute 也为空则没有明确的跳转地址了需要抛出异常 if(SaFoxUtil.isEmpty(redirect)) { if(SaFoxUtil.isEmpty(cfg.getHomeRoute())) { throw new SaSsoException(未指定 redirect 参数也未配置 homeRoute 路由无法完成重定向操作).setCode(SaSsoErrorCode.CODE_30014); } return cfg.getHomeRoute(); }由此可以确认两个关键行为有 SaSsoServerProcessorTest 单元测试印证已登录、无redirect、未配置homeRoute抛出 SSO 异常错误码30014定义见 SaSsoErrorCode已登录、无redirect、配置了homeRoute直接 302 重定向到homeRoute地址平台首页模式正是依赖这条分支。此外ssoAuth()中还有一个与平台模式相关的细节redirect参数会先经过SaFoxUtil.decoderUrlIfEncoded()做一次保险解码L120-L121因为各 web 容器对参数值的解码行为不统一这一层防御可以避免redirect中嵌套的?、等字符在传递过程中被破坏——这对本模式非常重要因为改造后的链接本身就是一条“参数里套参数”的深层 URL。四、第二步在 sso-server 编写平台中心首页 HomeController登录完成后的落点/home需要有真实的路由承载。仓库中的演示工程 HomeController 即为该模式的完整参考实现/** * SSO 平台中心模式示例跳连接进入子系统 */ RestController public class HomeController { // 平台化首页 RequestMapping({/, /home}) public Object index() { // 如果未登录则先去登录 if(!StpUtil.isLogin()) { return SaHolder.getResponse().redirect(/sso/auth); } // 拼接各个子系统的地址格式形如/sso/auth?clientxxxredirect${子系统首页}/sso/login?back${子系统首页} String link1 /sso/auth?clientsso-client3redirecthttp://sa-sso-client1.com:9003/sso/login?backhttp://sa-sso-client1.com:9003/; String link2 /sso/auth?clientsso-client3redirecthttp://sa-sso-client2.com:9003/sso/login?backhttp://sa-sso-client2.com:9003/; String link3 /sso/auth?clientsso-client3redirecthttp://sa-sso-client3.com:9003/sso/login?backhttp://sa-sso-client3.com:9003/; // 组织网页结构返回到前端 String title h2SSO 平台首页 (平台中心模式)/h2; String client1 pa href link1 target_blank 进入Client1系统 /a/p; String client2 pa href link2 target_blank 进入Client2系统 /a/p; String client3 pa href link3 target_blank 进入Client3系统 /a/p; return title client1 client2 client3; } }实现要点逐条说明未登录拦截/与/home两个路径均要求登录态未登录时通过SaHolder.getResponse().redirect(/sso/auth)跳回认证页。由于认证页此时不带redirect参数登录完成后会经由home-route回到本页面形成“登录 → 首页”闭环链接拼接规则每条子系统链接都遵循/sso/auth?client{client标识}redirect${子系统首页}/sso/login?back${子系统首页}格式。演示工程为了简化三条链接统一使用clientsso-client3模式三跨域跨 Redis且该 client 的allow-url配置为*因此三个不同域名的回调地址都能通过校验返回结构演示中直接拼接 HTML 字符串返回实际项目可替换为 Thymeleaf / Freemarker / 前端页面模板把 link1~link3 作为动态数据渲染甚至按用户角色过滤出有权限的子系统入口。演示工程的配套 application.yml 给出了完整的 Server 端配置参考节选server: port: 9000 sa-token: # SSO-Server 配置 sso-server: # Ticket有效期 (单位: 秒)默认五分钟 ticket-timeout: 300 # 主页路由在 /sso/auth 登录页不指定 redirect 参数时默认跳转的地址 home-route: /home # 是否启用匿名 client (开启匿名 client 后允许客户端接入时不提交 client 参数) allow-anon-client: true # 所有允许的授权回调地址 (匿名 client 使用) allow-url: * # API 接口调用秘钥 (全局默认 匿名 client 使用) secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor # 应用列表配置接入的应用信息 clients: # 应用 sso-client1采用模式一对接 (同域、同Redis) sso-client1: client: sso-client1 allow-url: * # 应用 sso-client2采用模式二对接 (跨域、同Redis) sso-client2: client: sso-client2 allow-url: * secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor # 应用 sso-client3采用模式三对接 (跨域、跨Redis) sso-client3: client: sso-client3 allow-url: * is-push: true push-url: http://sa-sso-client1.com:9003/sso/pushC secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor生产环境中需要注意allow-url是对redirect回调地址的白名单校验子系统回调地址必须落在对应 client 的 allow-url 范围内否则认证中心拒绝下发 ticket演示用*是图方便实际部署应收敛为具体的子系统域名。五、跳转链路纵深解析ticket 如何在一次跳转中完成免登录平台首页的链接只是“触发器”真正把用户免登录送进子系统的是 Sa-Token SSO 的 ticket 机制。从源码结构看完整调用链如下。第 1 跳用户点击链接到达 sso-server/sso/auth。用户此刻已持有认证中心登录态平台首页已保证ssoAuth()走“已登录”分支。由于链接中未带mode参数取默认值SaSsoConsts.MODE_TICKET见 SaSsoServerProcessor.java即走 ticket 模式// 方式2带着 ticket 参数重定向回Client端 (modeticket一般是模式二、三) String _redirectUrl ssoServerTemplate.buildRedirectUrl(client, redirect, stpLogic.getLoginId(), stpLogic.getTokenValue()); // 构建成功说明 redirect 地址合法此时需要更新一下当前 token 有效期 if(cfg.getAutoRenewTimeout()) { stpLogic.renewTimeout(stpLogic.getConfigOrGlobal().getTimeout()); } return _redirectUrl;即认证中心为当前登录用户生成一次性 ticket拼到redirect地址上形如http://sa-sso-client1.com:9003/sso/login?back...ticket...后 302 跳走。buildRedirectUrl内部会执行allow-url白名单校验与 client 校验非法回调地址在此被拦截。配置项autoRenewTimeout默认false控制是否在每次下发 ticket 时按全局timeout自动续期认证中心 token门户中心这种“高频跳转”场景可酌情开启避免用户频繁访问各子系统期间 token 过期。第 2 跳到达子系统/sso/login中转页。SaSsoClientProcessor.ssoLogin() 根据是否携带ticket参数分两条路public Object ssoLogin() { String ticket req.getParam(paramName.ticket); /* * 此时有两种情况: * 情况1ticket 无值说明此请求是 sso-client 端访问需要重定向至 sso-server 认证中心 * 情况2ticket 有值说明此请求从 sso-server 认证中心重定向而来需要根据 ticket 进行登录 */ if(ticket null) { return _goServerAuth(); } else { return _loginByTicket(); } }本模式中用户带着 ticket 到达进入_loginByTicket()L228-L254校验 ticket 换出loginId、deviceId、剩余 token 有效期等信息调用stpLogic.login(...)在子系统本地建立登录态最后 302 到back参数指定的子系统首页。ticket 校验有两种实现由 client 端is-http配置决定见 SaSsoClientProcessor.checkTicket()is-httptrue模式三跨域跨 Redis子系统通过 HTTP 请求带签名向认证中心校验 ticketis-httpfalse模式二跨域同 Redis子系统直连 Redis 校验并删除 ticket省一次网络往返。ticket 是一次性凭证认证成功后即被删除checkTicketParamAndDelete有效期由ticket-timeout控制默认 300 秒演示配置同。这保证了即便跳转链接被截取也无法重复利用来登录。一个值得注意的短路逻辑若子系统发现当前其实已登录_goServerAuth()中 L209-L211 的stpLogic.isLogin()判断则不再访问认证中心直接重定向回back。也就是说平台首页链接对“已登录该子系统的用户”是一次零成本的普通跳转只有首次进入或会话过期时才会走完整 ticket 链路。六、验证与测试集成验证启动 sso-server 演示工程后访问http://sa-sso-server.com:9000演示环境域名本地可用localhost:9000。首次访问因未登录被重定向到/sso/auth登录页登录成功后由于请求中无redirect参数认证中心按home-route: /home重定向到平台首页随后依次点击三个子系统链接浏览器在跳转的同时自动登录对应子系统。单元测试印证SaSsoServerProcessorTest 对home-route相关分支做了精确覆盖ssoAuth_loggedInEmptyRedirectNoHome_throws30014已登录、无 redirect、无 homeRoute → 断言抛出30014ssoAuth_loggedInEmptyRedirectHasHome_redirectsHome已登录、无 redirect、配置homeRoute→ 断言重定向目标等于 homeRoutessoAuth_modeTicket_containsTicketAndRedirect默认 ticket 模式下redirect 上会拼出ticket参数。七、落地时的注意事项home-route未配置且无 redirect 会报 30014平台中心模式必须配置该项否则用户直接访问认证中心登录后无处可去redirect 是“参数套参数”的深层 URL认证中心已内置decoderUrlIfEncoded防御性解码SaSsoServerProcessor.java但前端自行渲染链接时仍建议确保redirect值按 URL 规范传递避免二次编码问题allow-url 白名单必须覆盖各子系统回调地址演示中三条链接统一使用clientsso-client3且allow-url: *生产环境建议每个子系统使用独立 client 标识并将 allow-url 收敛到各自域名ticket 一次性 时效性不要试图缓存/复用跳转链接中的 ticket跨域跨 Redis 的子系统请保持secret-key与认证中心配置一致is-check-sign生产环境务必为 true配置项默认值见 SaSsoServerConfig首页权限裁剪HomeController可按登录用户的角色/权限动态生成入口列表把“平台中心”从统一导航页升级为按角色呈现的应用市场。综上Sa-Token 的平台中心跳转模式并不引入额外协议它复用了 SSO 既有的/sso/auth授权入口与 ticket 免登录机制仅靠home-route配置 首页链接的格式约定就把“认证中心”升级为“认证中心 统一门户”实现一处登录、全系统免登通行。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表