1. 为什么选择 Sa-Token 来做前后端分离的 SSO?
如果你正在开发一个中后台系统,或者一个包含多个子系统的微服务架构,那你肯定遇到过这个头疼的问题:用户需要在每个系统里都登录一遍,体验极差。单点登录(SSO)就是为了解决这个痛点而生的。简单说,就是用户在一个地方登录,就能畅通无阻地访问所有互相信任的系统。
那为什么我推荐用 Sa-Token 来实现呢?我踩过不少坑,试过自己手撸 Token 校验,也折腾过 Spring Security 和 CAS,最后发现 Sa-Token 在前后端分离场景下,简直是“开箱即用”的代名词。它不像一些重型框架,需要你理解一大堆复杂的概念和配置。Sa-Token 的设计哲学就是“简单”,它把 SSO 的复杂流程封装成了几个清晰的模式,你只需要根据你的架构选对模式,照着文档配一下,基本就通了。
尤其是在前后端分离成为主流的今天,传统的基于 Cookie-Session 的 SSO 方案基本失灵。因为你的 Vue 前端跑在 localhost:8080,后端服务在 localhost:9001,认证中心又在 localhost:9000,跨域是家常便饭。Sa-Token 的 SSO 模块天生就为这种场景做了优化,它通过 Ticket(票据)机制在多个系统间安全地传递登录状态,而不是依赖浏览器 Cookie。这意味着你的手机 App、小程序、或者纯粹的 API 服务,都能轻松接入这套单点登录体系。
我印象最深的是它的“参数防丢失”特性。早期我用别的方案时,经常遇到用户从商品详情页(带了一堆参数如productId=123)跳转到登录页,登录成功后,参数全丢了,用户又得重新找。Sa-Token 内部有专门的算法处理这个,保证登录成功后能“原路返回”,用户体验提升了一大截。所以,如果你正在为多个系统间的统一登录发愁,特别是前后端分离架构,Sa-Token 绝对值得你花一个下午试试。
2. 五分钟搞懂 Sa-Token SSO 的三种核心模式
在动手敲代码之前,咱们得先搞清楚 Sa-Token SSO 提供的三种模式,这决定了你后续的架构和配置。别担心,我用最直白的话给你解释清楚。
模式一:同域 + 同 Redis。这是最简单的一种,要求你的所有子系统(比如oa.company.com,crm.company.com)使用同一个主域名,并且后端都连接同一个 Redis。它的原理是利用了 Cookie 的“域”特性,在认证中心登录后,Cookie 可以共享给同域下的其他子系统,同时会话数据都存到同一个 Redis,大家都能读到。这种模式适合传统单体应用拆分的微服务,且部署在同一个域名下。
模式二:不同域 + 同 Redis。这才是前后端分离和微服务架构下最常用的模式!你的前端项目(Vue)和后端服务(SpringBoot)可能域名、端口都不同,完全跨域。但只要你们所有的后端服务(包括认证中心sso-server和各个业务系统sso-client)能访问同一个 Redis 就行。它的流程是:前端访问业务系统时,发现没登录,就带着当前地址重定向到认证中心;用户在认证中心登录后,会生成一个一次性的Ticket票据,并随着重定向带回业务系统;业务系统拿着这个Ticket去认证中心校验,校验通过后就在本地登录,并创建自己的会话。全程通过 URL 重定向和 Redis 共享数据完成,完美解决跨域问题。
模式三:不同域 + 不同 Redis。这是最通用、限制最少的“兜底”模式。各个系统连自己的 Redis,甚至不是 Java 技术栈(比如 PHP、Python)也能接入。它的通信方式从共享 Redis 变成了直接的 HTTP 接口调用。业务系统校验 Ticket 时,直接发 HTTP 请求到认证中心。这种模式灵活性最高,但网络通信开销稍大,且需要认证中心提供对外的 HTTP 校验接口。
对于我们今天的主题——SpringBoot + Vue2 前后端分离,模式二是最贴合、最推荐的选择。我们的实战也将基于此展开。你只需要记住一个核心:认证中心是唯一负责“验明正身”的地方,它颁发 Ticket;各个业务系统是“凭票入场”的地方,它们校验 Ticket 并在本地维持会话。
3. 手把手搭建认证中心(sso-server)
好了,理论说完,咱们动真格的。首先来搭建整个单点登录体系的核心——认证中心。你可以把它理解成集团的“总部前台”,所有员工(用户)都得在这里登记。
第一步:创建 SpringBoot 项目并引入依赖。用你喜欢的 IDE(IDEA 或 VS Code)创建一个普通的 SpringBoot 项目,名字就叫sso-server。然后打开pom.xml,关键依赖就下面这几个:
<!-- Sa-Token 核心包 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.44.0</version> <!-- 请使用最新稳定版 --> </dependency> <!-- Sa-Token SSO 插件 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-sso</artifactId> <version>1.44.0</version> </dependency> <!-- Sa-Token 集成 Redis(使用Jackson序列化,推荐) --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-redis-jackson</artifactId> <version>1.44.0</version> </dependency> <!-- Redis连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- Web支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>第二步:配置 application.yml。这里配置了服务器端口、Sa-Token 的 SSO 参数以及 Redis 连接。注意看注释:
server: port: 9000 # 认证中心端口 sa-token: # SSO-模式二相关配置 sso: # Ticket有效期,单位秒,默认5分钟 ticket-timeout: 300 # 允许所有授权回调地址(生产环境请配置具体地址) allow-url: "*" # Token风格,保持默认uuid即可 token-style: uuid spring: redis: # 连接同一个Redis,这是模式二的关键! database: 0 host: 127.0.0.1 port: 6379 password: # 如果你的Redis有密码就填上 lettuce: pool: max-active: 8 max-wait: -1ms max-idle: 8 min-idle: 0第三步:编写核心控制器。我们需要创建一个SsoServerController,它有两个核心作用:处理所有 SSO 相关请求,以及配置登录逻辑。
import cn.dev33.satoken.config.SaSsoConfig; import cn.dev33.satoken.sso.SaSsoProcessor; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * SSO-Server端:认证中心控制器 */ @RestController public class SsoServerController { /** * 处理所有SSO请求的入口 * 比如:/sso/auth, /sso/doLogin, /sso/checkTicket 等 */ @RequestMapping("/sso/*") public Object ssoRequest() { return SaSsoProcessor.instance.serverDister(); } /** * 配置SSO登录处理逻辑 * 这个方法会被Sa-Token自动调用进行配置 */ @Autowired public void configSso(SaSsoConfig sso) { // 设置登录处理函数 sso.setDoLoginHandle((username, password) -> { // 这里应该是查询数据库进行验证,这里我们简单模拟 if ("admin".equals(username) && "123456".equals(password)) { // 登录成功,参数是用户id,这里我们模拟id为10001的用户 StpUtil.login(10001); // 返回成功信息,并把Token值带给前端 return SaResult.ok("登录成功").setData(StpUtil.getTokenValue()); } return SaResult.error("登录失败:账号或密码错误"); }); } }这里有个小技巧:setDoLoginHandle函数里,如果你需要除了账号密码以外的参数(比如验证码),可以通过SaHolder.getRequest().getParam(“verifyCode”)来获取,非常灵活。
第四步:解决跨域问题。因为前端 Vue 项目会直接请求这个认证中心进行登录,所以必须配置跨域。创建一个全局过滤器:
import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component @Order(-200) // 优先级设置很高 public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; // 允许所有域访问(生产环境应指定具体域名) response.setHeader("Access-Control-Allow-Origin", "*"); // 允许的请求方法 response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); // 预检请求缓存时间 response.setHeader("Access-Control-Max-Age", "3600"); // 允许的请求头,注意加上 satoken response.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, satoken"); // 如果是OPTIONS预检请求,直接返回成功 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(req, res); } }启动这个sso-server项目,访问http://localhost:9000如果没报错,你的“总部前台”就搭建好了。接下来,我们需要一个“分公司”来测试。
4. 快速创建客户端系统(sso-client)
现在我们来搭建一个需要接入单点登录的业务系统,也就是客户端。流程和认证中心类似,但配置侧重点不同。
第一步:创建项目并引入依赖。再创建一个 SpringBoot 项目,叫sso-client。pom.xml依赖和sso-server几乎一样,确保版本一致即可。
第二步:配置客户端 application.yml。这里的配置是关键,它指明了认证中心在哪里,以及自己如何连接 Redis。
server: port: 9001 # 客户端端口,必须和认证中心不同 sa-token: # SSO-客户端配置 sso: # 认证中心地址(就是sso-server的地址) auth-url: http://127.0.0.1:9000/sso/auth # 是否开启单点注销 is-slo: true # 客户端单独使用的Redis配置(必须和server连同一个Redis实例!) alone-redis: database: 0 # 可以和server用同一个库,也可以不同,但实例要一样 host: 127.0.0.1 port: 6379 password: timeout: 10s lettuce: pool: max-active: 8 max-wait: -1ms max-idle: 8 min-idle: 0第三步:编写客户端认证接口。客户端需要提供几个标准接口,供前端和认证中心回调。
import cn.dev33.satoken.sso.SaSsoProcessor; import cn.dev33.satoken.sso.SaSsoUtil; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SsoClientController { // 检查当前在本系统是否已登录 @RequestMapping("/sso/isLogin") public Object isLogin() { return SaResult.data(StpUtil.isLogin()); } // 获取跳转到认证中心的地址(前端发起登录时用) @RequestMapping("/sso/getSsoAuthUrl") public SaResult getSsoAuthUrl(String redirectUrl) { String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(redirectUrl, ""); return SaResult.data(serverAuthUrl); } // 核心:根据Ticket进行登录(认证中心回调此接口) @RequestMapping("/sso/doLoginByTicket") public SaResult doLoginByTicket(String ticket) { // 使用Processor校验ticket Object loginId = SaSsoProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket"); if(loginId != null) { // 校验成功,在本系统登录对应用户 StpUtil.login(loginId); // 可以将token返回,但前后端分离模式下通常由前端自己从header读 return SaResult.ok("客户端登录成功").setData(StpUtil.getTokenValue()); } return SaResult.error("无效ticket:" + ticket); } // 全局异常处理 @ExceptionHandler public SaResult handlerException(Exception e) { e.printStackTrace(); return SaResult.error(e.getMessage()); } }第四步:同样配置跨域过滤器。把上面sso-server里的CorsFilter类原封不动地复制到客户端项目里。因为你的 Vue 前端也会直接请求这个客户端接口。
第五步:配置本地 hosts 文件(可选但推荐)。为了模拟真实的多域名环境,我们修改一下本机的 hosts 文件(C:\Windows\System32\drivers\etc\hosts或/etc/hosts),添加两行:
127.0.0.1 sa-sso-server.com 127.0.0.1 sa-sso-client.com这样,我们就可以用http://sa-sso-server.com:9000访问认证中心,用http://sa-sso-client.com:9001访问客户端,更像真实的跨域场景了。现在,启动sso-client。后端部分就全部准备好了!是不是感觉没那么复杂?核心就是两个配置文件和几个标准的接口。接下来,我们要让前端“动”起来。
5. 构建 Vue2 前端项目并实现登录跳转
前端是用户直接交互的地方,也是前后端分离架构下 SSO 流程的“串联者”。我们用一个简单的 Vue2 项目来演示。如果你已经有一个现成的 Vue 项目,可以直接集成;如果没有,可以用 Vue CLI 快速创建一个。
第一步:准备前端项目。假设你已经有了一个 Vue2 项目,安装了axios用于网络请求。我们需要两个页面:一个主页面(受保护,需要登录才能看),一个登录回调页面(用于处理认证中心跳转回来的 Ticket)。
第二步:实现核心登录逻辑。我们在主页面(比如Home.vue)的created或mounted钩子中,检查登录状态。
<template> <div> <h1>客户端主页</h1> <p v-if="isLogin">欢迎您,已登录用户!</p> <p v-else>您还未登录,<button @click="toLogin">请登录</button></p> <button @click="logout" v-if="isLogin">退出登录</button> </div> </template> <script> import axios from 'axios'; // 配置axios基地址,指向我们的sso-client后端 axios.defaults.baseURL = 'http://sa-sso-client.com:9001'; export default { name: 'Home', data() { return { isLogin: false }; }, mounted() { this.checkLogin(); }, methods: { // 检查在本系统是否登录 async checkLogin() { try { const res = await axios.get('/sso/isLogin'); this.isLogin = res.data.data; // 返回true/false } catch (error) { console.error('检查登录状态失败', error); this.isLogin = false; } }, // 跳转到认证中心登录 toLogin() { // 重要:构造当前页面的地址作为登录成功后的回调地址 const currentUrl = encodeURIComponent(window.location.href); // 请求客户端后端,获取认证中心的完整登录地址 axios.get(`/sso/getSsoAuthUrl?redirect=${currentUrl}`) .then(res => { if (res.data.code === 200) { // 跳转到认证中心 window.location.href = res.data.data; } else { alert('获取登录地址失败'); } }); }, // 退出登录 async logout() { // 调用Sa-Token的注销接口 await axios.post('/sso/logout'); this.isLogin = false; alert('已退出'); } } }; </script>第三步:创建登录回调页面。这是整个流程的“魔法发生地”。当用户在认证中心登录成功后,会被重定向回这个页面,并附带一个ticket参数。这个页面的任务就是把这个ticket交给客户端后端去校验。
<!-- SsoCallback.vue --> <template> <div> <p>正在登录验证,请稍候...</p> </div> </template> <script> import axios from 'axios'; axios.defaults.baseURL = 'http://sa-sso-client.com:9001'; export default { name: 'SsoCallback', mounted() { this.handleCallback(); }, methods: { async handleCallback() { // 从URL参数中获取ticket const urlParams = new URLSearchParams(window.location.search); const ticket = urlParams.get('ticket'); if (!ticket) { alert('登录失败:未接收到有效票据'); this.$router.push('/'); return; } try { // 将ticket发送给客户端后端进行校验和登录 const res = await axios.get(`/sso/doLoginByTicket?ticket=${ticket}`); if (res.data.code === 200) { // 登录成功!获取后端返回的token(如果需要) const token = res.data.data; // 通常前后端分离模式下,token由后端自动注入到响应头,前端axios拦截器统一处理 // 这里我们简单提示并跳回主页 alert('登录成功!'); // 替换历史记录,避免回退到带ticket的URL this.$router.replace('/'); } else { alert('登录失败:' + res.data.msg); this.$router.push('/'); } } catch (error) { console.error('登录过程异常', error); alert('网络或服务器错误'); this.$router.push('/'); } } } }; </script>第四步:配置前端路由。在你的router/index.js里,添加这个回调页面的路由。
import Vue from 'vue'; import VueRouter from 'vue-router'; import Home from '../views/Home.vue'; import SsoCallback from '../views/SsoCallback.vue'; Vue.use(VueRouter); const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/sso-callback', // 这个路径需要和认证中心配置的回调地址对应 name: 'SsoCallback', component: SsoCallback } ]; const router = new VueRouter({ mode: 'history', // 推荐使用history模式,URL更简洁 routes }); export default router;第五步:配置 axios 拦截器处理 Token。这是前后端分离的另一个关键:如何让后续的 API 请求都带上登录凭证。我们在前端请求拦截器里,从本地存储(比如 localStorage)读取 token,并塞到请求头里。
// 在main.js或单独的axios配置文件中 import axios from 'axios'; // 请求拦截器 axios.interceptors.request.use( config => { // 从localStorage获取token(假设登录成功后我们存了) const token = localStorage.getItem('satoken'); if (token) { // Sa-Token默认的header名称就是‘satoken’ config.headers['satoken'] = token; } return config; }, error => { return Promise.reject(error); } ); // 响应拦截器(处理401未登录等状态) axios.interceptors.response.use( response => { return response; }, error => { if (error.response && error.response.status === 401) { // 遇到401,跳转到登录页 // 注意:这里不能直接用router,因为可能不在Vue上下文 window.location.href = '/#/'; // 或者触发一个全局事件让Vue组件处理 } return Promise.reject(error); } );至此,一个完整的前后端分离 SSO 流程的前端部分就实现了。它的核心思路是:前端不直接处理密码登录,只负责引导用户到认证中心,并处理认证中心回调的票据。
6. 联调测试与全流程深度解析
所有部件都准备好了,让我们启动所有服务,来一次完整的“阅兵”,看看整个流程是如何无缝衔接的。请按顺序启动:1. Redis 服务;2.sso-server(端口9000);3.sso-client(端口9001);4. Vue 前端项目 (比如端口8080)。
测试场景一:首次访问客户端主页。
- 打开浏览器,访问
http://localhost:8080(Vue主页)。 - 主页组件
Home.vue加载,执行checkLogin(),调用客户端后端接口http://sa-sso-client.com:9001/sso/isLogin。 - 此时客户端后端检查会话,发现用户未登录,返回
false。 - 前端页面显示“未登录”状态和登录按钮。
- 你点击“登录”按钮,触发
toLogin()方法。
测试场景二:跳转认证中心登录。
toLogin()方法先获取当前页面URL作为回调地址,然后请求客户端后端的/sso/getSsoAuthUrl。- 客户端后端根据配置的
auth-url,生成一个指向认证中心的完整URL,并附带上回调地址,例如:http://sa-sso-server.com:9000/sso/auth?redirect=xxx&client=xxx。 - 前端收到这个URL,直接
window.location.href跳转过去。 - 浏览器此时打开了认证中心的登录页面(这个页面需要你单独准备一个简单的HTML,或者用Sa-Token提供的QuickLogin插件,我们前面在server配置的
setDoLoginHandle就是处理这个页面提交的)。
测试场景三:在认证中心完成认证。
- 你在认证中心页面输入账号
admin,密码123456,点击登录。 - 请求发到
sso-server的/sso/doLogin(由SsoServerController中的ssoRequest()统一路由处理)。 - 认证中心执行我们配置的登录逻辑,验证通过后,调用
StpUtil.login(10001)。关键一步来了:此时,认证中心会生成一个一次性的、有时效的Ticket(比如一串随机字符),并将用户ID(10001)和这个Ticket的对应关系存入共享的Redis中。 - 认证中心然后带着这个
Ticket,重定向回最初客户端提供的回调地址,也就是我们的 Vue 回调页面http://localhost:8080/sso-callback?ticket=xxxxxx。
测试场景四:客户端校验Ticket完成本地登录。
- Vue 的
SsoCallback.vue页面被加载,它在mounted钩子中提取URL里的ticket参数。 - 页面将这个
ticket发送给自己的后端sso-client,请求/sso/doLoginByTicket接口。 - 客户端后端收到请求,它自己并不直接信任这个ticket,而是通过
SaSsoProcessor.instance.checkTicket()方法,向认证中心发起一个内部验证请求(或者根据模式二,直接从共享Redis中检查这个ticket是否存在且有效)。 - 验证通过!认证中心(或Redis)返回这个ticket对应的用户ID:10001。验证成功后,这个ticket会被立即销毁,防止被重复使用。
- 客户端后端拿到用户ID 10001,调用
StpUtil.login(10001)。注意,这是在客户端系统内部创建了一个新的会话,生成一个属于客户端自己的token,并存入客户端所连的Redis(实际上和认证中心是同一个Redis实例,但逻辑上是独立的会话)。 - 客户端登录成功,返回前端。前端跳转回主页。
- 主页再次检查登录状态
isLogin,这次客户端后端发现有本地会话了,返回true。前端显示“欢迎您,已登录用户!”。
整个流程的精髓在于:认证中心是“发证机关”,它签发的Ticket是“一次性介绍信”。各个业务系统是“接待单位”,它们凭“介绍信”(Ticket)去“发证机关”核验身份,核验成功后,在自己的地盘(本地会话)为这位用户建立档案。从此以后,用户访问这个业务系统,就只看本地的档案(Token),不再需要每次都去认证中心了。这种设计既安全(Ticket一次性),又高效(后续访问无额外校验),完美契合分布式架构。
7. 实战中必知的进阶配置与坑点指南
按照上面的步骤走通基本流程后,你已经成功了80%。但想在实际项目中稳健落地,还有20%的细节和“坑”需要注意。这些是我在多个项目中总结出来的经验。
第一,安全配置收紧。演示时我们用了allow-url: “*”允许所有回调地址,这在生产环境是极度危险的。必须改为精确配置:
# sso-server的application.yml sa-token: sso: allow-url: “http://your-vue-domain.com/sso-callback, http://another-client.com/sso-login”同样,跨域过滤器CorsFilter中的Access-Control-Allow-Origin也不要再用“*”,改成具体的前端域名。
第二,Token持久化与自动续签。默认情况下,Sa-Token 的 Token 有效期是30天,且关闭浏览器后会话就丢失(因为默认是临时会话)。对于需要“记住我”功能的系统,你需要配置:
sa-token: # 设置token有效期为7天 timeout: 604800 # 设置活跃期续签,只要在有效期内有访问,token有效期就重置为timeout active-timeout: -1 # 允许持久化会话,即使浏览器关闭再打开,只要token未过期,依然登录 is-share: true注意,is-share: true需要配合持久化存储(如Redis)才能生效。
第三,优雅处理前端路由与404。在Vue的history模式下,当你直接刷新一个子路由页面(如/user/profile)时,浏览器会向你的静态资源服务器请求这个路径,导致404。你需要在后端(比如Nginx)或前端开发服务器配置,将所有非静态文件请求都回退到index.html。另外,在SsoCallback.vue中,登录成功后我们用了this.$router.replace(‘/’)来清除URL中的ticket参数,这是一个好习惯。
第四,用户信息同步问题。我们的流程只同步了用户ID(loginId)。但业务系统通常还需要用户名、头像等详细信息。有两种常见做法:
- 客户端自行查询:登录成功后,客户端根据拿到的用户ID,调用自己的用户服务或一个统一的用户中心接口获取详细信息。这要求各系统共享用户数据源。
- 认证中心携带:在认证中心生成Ticket时,可以将一些基本用户信息加密后一并传给客户端(Sa-Token支持自定义Ticket内容)。客户端校验Ticket后就能解密出信息,无需再次查询。这种方式更高效,但增加了认证中心的负担和耦合度。
第五,单点注销的实现。我们配置了is-slo: true,这意味着在一个系统退出登录,会通知认证中心,认证中心再通知所有其他已登录的系统一起退出。你需要在前端退出按钮的logout方法中,调用正确的注销接口。通常,调用客户端自己的/sso/logout即可,这个接口会联动处理。
第六,本地开发环境调试技巧。如果你在调试时发现一直循环重定向,或者Ticket无效,请按以下顺序排查:
- 检查Redis:确保Redis服务正常,并且
sso-server和sso-client连接的是同一个Redis实例和数据库。可以用Redis桌面工具看看登录时有没有数据写入。 - 检查跨域:打开浏览器开发者工具的“网络(Network)”面板,查看每一次重定向和Ajax请求的请求头和响应头,确认
Access-Control-Allow-*头是否正确。 - 检查地址:确认
sso-client配置的auth-url和前端跳转的地址,与sso-server的实际运行地址完全一致,不要混用localhost、127.0.0.1和sa-sso-server.com,建议统一用配置了hosts的域名。 - 查看日志:在
sso-server和sso-client的后台控制台,打开Sa-Token的详细日志,通常能清晰地看到每一步的校验过程和失败原因。在application.yml中增加logging.level.cn.dev33: DEBUG可以开启调试日志。
把这些进阶点都处理好,你的 Sa-Token SSO 集成就算真正成熟了。它不再是一个demo,而是一个可以支撑起多系统统一认证的坚实基础设施。