Featured image of post sa-token SSO 单点登录三种模式完整实战

sa-token SSO 单点登录三种模式完整实战

sa-token SSO 单点登录三种接入模式(同域共享 Cookie、跨域 ticket 码、跨域跨 Redis 主动查询)的接口规范、服务端/客户端配置、ReSdk 模式深度实战

sa-token 是国内 Dromara 组织下的轻量级 Java 权限认证框架,2021 年 GitHub star 数超过 8k。sa-token 的 SSO 模块是国内最简洁的 Java 单点登录方案之一——它把 SSO 抽象成三种"客户端-服务端"模式,让不同业务场景都能找到合适方案。本文基于 sa-token 1.44.0 版本做一次完整实战。

本文写于 2021 年 12 月——sa-token SSO 模块稳定迭代后的版本。

一、SSO 接口规范

sa-token 定义了一套标准的 SSO RESTful 接口规范,所有模式都遵循这套接口:

1.1 服务端(SSO-Server)接口

接口解释
server/sso/auth单点登录授权(重定向到登录页)
server/sso/doLoginrestapi 登录接口(自定义 doLoginHandle
server/sso/signout单点登录注销
server/sso/pusS消息推送(模式三服务端推送)
server/sso/userinfo获取用户信息(自定义)

1.2 客户端(SSO-Client)接口

接口解释
client/sso/login客户端登录地址(重定向到 server)
client/sso/logout客户端注销
client/sso/logoutCall单点注销回调
client/sso/pusC消息推送(模式三客户端接收)
client/sso/myInfo客户端查询用户信息

特点

  • 所有接口都是基于 HTTP 的 RESTful
  • 通过 redirect 参数传递回调地址
  • 模式三需要主动 HTTP 推送(基于 Forest HTTP 工具)

二、SSO 模式一:前端同域 + 后端同 Redis

2.1 原理

共享 Cookie 来做到前端 Token 的共享,从而达到后端的 Session 会话共享:

1
2
3
4
5
App1(a.example.com)  ──┐
                          │ 同域 stp.com 共享 Cookie
App2(a.example.com)  ──┤
                          │ 同 Redis 共享 Session
App3(a.example.com)  ──┘

架构

  • 所有应用挂在同一个域下(如 stp.com
  • 登录后 Cookie 写入 stp.com
  • 后续访问任何应用都自动带上 Cookie
  • Session 存储在同一个 Redis

2.2 优点

  • 最简单:零额外开发
  • 最稳定:基于 Cookie + Redis 标准方案
  • 最高性能:无重定向,无额外 HTTP 请求

2.3 缺点

  • 必须同域:所有应用必须挂在同一个父域下
  • 不能跨域:如果是不同根域的多个产品线,不能用此模式

2.4 适用场景

  • 同公司多个子系统(如 crm.stp.comerp.stp.comoa.stp.com
  • 微服务架构内部系统

三、SSO 模式二:前端不同域 + 后端同 Redis

3.1 原理

采用 URL 重定向,以 ticket 码为授权中介,做到多个系统间的会话传播:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
App1(a.com)              App2(b.com)
  │                          │
  │  ① /sso/auth?redirect=   │
  ▼                          │
SSO-Server(sso.com)        │
  │                          │
  │  ② 重定向到 /sso/login   │
  ▼                          │
登录页(sso.com)            │
  │                          │
  │  ③ 提交账密               │
  ▼                          │
SSO-Server                  │
  │                          │
  │  ④ 颁发 ticket + 重定向  │
  │     /sso/login?ticket=xxx│
  ▼                          │
  ┌─────────────────────────▶│
  │                          ▼
  │                    App2 回调 /sso/login?ticket
  │                          │
  │                          ▼
  │                    携带 ticket 调用 SSO-Server /sso/authTicket
  │                          │
  │                          ▼
  │                    SSO-Server 校验 ticket
  │                          │
  │                          ▼
  │                    返回 App2 的 token,写入 App2 的 Session

关键流程

  1. 用户访问 App1(a.com)
  2. App1 发现自己未登录,重定向到 SSO-Server /sso/auth?redirect=...
  3. SSO-Server 发现自己未登录,返回登录页
  4. 用户登录成功,SSO-Server 生成 ticket 写入 Redis
  5. SSO-Server 重定向回 App1 redirect 地址,带上 ticket
  6. App1 拿到 ticket,调用 SSO-Server /sso/authTicket 换 App1 的 token
  7. App1 把 token 写入自己的 Session
  8. 用户访问 App2(b.com),重复同样流程,但 SSO-Server 已经认识这个用户,自动颁发 ticket(无需再登录)

3.2 优点

  • 支持跨域:不同根域的应用可以登录
  • 基于 ticket:标准 OAuth 2.0 风格
  • 无状态:ticket 一次有效,换完即失效

3.3 缺点

  • 有重定向:首次访问慢一点
  • 配置复杂:需要给每个应用配置 client 名称 + 回调地址

3.4 适用场景

  • 不同子公司的多个产品(如 aliyun.comdingtalk.comalipay.com
  • 企业 SaaS 多租户

四、SSO 模式三:前端不同域 + 后端不同 Redis

4.1 原理

采用 Http 请求主动查询会话,做到 Client 端与 Server 端的会话同步:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
App1(a.com)            App2(b.com)
  │                          │
  │                          │  ① /sso/login?redirect=...
  │                          ▼
  │                    SSO-Server(sso.com)
  │                          │
  │                          │  ② ticket=xxx
  │                          ▼
  │                    App2 调用 /sso/authTicket 换 token
  │                          │
  │                          ▼
  │                    SSO-Server 主动 HTTP 推送
  │                          │  /sso/pusC
  │                          ▼
  │                    App1 也收到推送(同步登录状态)
  │  ③ 收到推送,已登录
  全员同步

关键流程

  1. App2 主动调用 SSO-Server 的 /sso/authTicket 验证 ticket
  2. SSO-Server 验证通过后,主动通过 HTTP POST 推送消息到所有已注册的客户端
  3. 所有 App(包括 App1、App2、App3)都收到推送
  4. 所有 App 同步更新本地 Session

4.2 优点

  • 真正的分布式:不需要共享 Session
  • 实时同步:注销、踢人、状态变更实时通知
  • 可扩展:App1/2/3/4 任意上下线不影响

4.3 缺点

  • 需要 HTTP 推送:依赖 Forest HTTP 客户端
  • 推送失败容错:推送失败时需要心跳轮询兜底

4.4 适用场景

  • 跨数据中心部署(各应用在不同地域的 Redis)
  • 超大规模 SSO(上百个应用)

五、服务端(SSO-Server)实战

5.1 依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!-- SpringBoot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.14</version>
</parent>

<properties>
    <sa-token.version>1.44.0</sa-token.version>
</properties>

<dependencies>
    <!-- SpringBoot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Sa-Token 核心 -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-spring-boot-starter</artifactId>
        <version>${sa-token.version}</version>
    </dependency>

    <!-- Sa-Token SSO 插件 -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-sso</artifactId>
        <version>${sa-token.version}</version>
    </dependency>

    <!-- Sa-Token Redis 集成 -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-redis-template</artifactId>
        <version>${sa-token.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>

    <!-- Thymeleaf(前后端不分离模式) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <!-- Forest HTTP 客户端(模式三需要) -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-forest</artifactId>
        <version>${sa-token.version}</version>
    </dependency>
</dependencies>

5.2 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
server:
  port: 9000

# Sa-Token 配置
sa-token:
  is-log: true

  # SSO-Server 配置
  sso-server:
    # Ticket 有效期(单位:秒),默认 5 分钟
    ticket-timeout: 300
    # 主页路由:在 /sso/auth 登录页不指定 redirect 参数时,默认跳转的地址
    home-route: /home
    # 是否启用匿名 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/pusC
        secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
      # 应用 sso-client3-resdk:采用 ReSdk 模式对接
      sso-client3-resdk:
        client: sso-client3-resdk
        allow-url: "*"
        is-push: true
        push-url: http://sa-sso-client1.com:9005/sso/pusC
        secret-key: SSO-C3-ReSdk-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor

# Redis 配置
spring:
  redis:
    database: 1
    host: 127.0.0.1
    port: 6379
    password:
    timeout: 10s
    lettuce:
      pool:
        max-active: 200
        max-wait: -1ms
        max-idle: 10
        min-idle: 0

# Forest HTTP 客户端
forest:
  log-enabled: false

5.3 hosts 配置

1
2
# 模拟多域名环境
127.0.0.1 sa-sso-server.com

5.4 测试入口

1
登录页:http://sa-sso-server.com:9000/sso/auth

六、客户端实战

6.1 标准模式客户端

同模式二客户端配置(sso-client2):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server:
  port: 9002

sa-token:
  sso-client:
    # SSO-Server 域名
    server-url: http://sa-sso-server.com:9000
    # 本应用 Client 标识
    client: sso-client2
    # 本应用密钥(与 Server 端配置一致)
    secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
    # 登录回调地址
    redirect-url: http://sa-sso-client2.com:9002/sso/login

6.2 ReSdk 模式客户端

ReSdk 是 sa-token 提供的一种不依赖 Spring MVC 拦截器的接入方式,适合老项目改造:

1
2
3
4
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-sso</artifactId>
</dependency>

优点

  • 业务代码侵入小(只需在 Controller 入口加 1-2 行)
  • 支持非 Spring 项目
  • 支持 GraalVM Native Image

6.3 NoSdk 模式客户端

完全不依赖 Sa-Token,纯 HTTP 调用 SSO 接口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<dependencies>
    <!-- SpringBoot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Forest HTTP 客户端 -->
    <dependency>
        <groupId>com.dtflys.forest</groupId>
        <artifactId>forest-spring-boot-starter</artifactId>
        <version>1.5.26</version>
    </dependency>
</dependencies>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
server:
  port: 9004

forest:
  log-request: true

spring:
  redis:
    database: 2
    host: 127.0.0.1
    port: 6379
    timeout: 10s
    lettuce:
      pool:
        max-active: 200
        max-wait: -1ms
        max-idle: 10
        min-idle: 0

自定义接口

接口含义
/client-首页
/sso/loginclient-登录
/sso/logoutclient-单点注销
/sso/logoutCallclient-单点注销回调
/sso/myInfoclient-查询用户信息(sso-server 开放了 /sso/userinfo 路由)

hosts

1
2
3
127.0.0.1 sa-sso-client1
127.0.0.1 sa-sso-client2
127.0.0.1 sa-sso-client3

七、模式选型决策树

八、写在最后

sa-token 的 SSO 模块是国内 Java 单点登录的标杆方案——配置简单、模式丰富、社区活跃

个人建议

  • 同公司多子系统:模式一(同域)最快
  • 不同根域多产品线:模式二(跨域 ticket)最经典
  • 跨数据中心部署:模式三(跨域跨 Redis 推送)最稳
  • 老项目改造:ReSdk 模式侵入最小
  • 彻底解耦:NoSdk 模式只走 HTTP

参考资料

九、2024+ 视角:sa-token 1.38+ → 1.44+、OAuth2.0 与 OIDC 完整支持

本文写于 2021 年 12 月(sa-token 1.44.0 时代),sa-token 在 2024-2025 年完成了一次"质变"——从"权限认证"扩展为"OAuth2.0 / OIDC 全家桶"。

9.1 sa-token 版本演进(2021 → 2025)

版本时间关键变化
1.30.x2021-06基础 SSO 三模式(本文写于 1.44.0 之后,2021-12)
1.34.x2023-08新增 OAuth2.0 完整模块(authorization_code / client_credentials / password)
1.36.x2024-02新增 OIDC(OpenID Connect)模块,IdP / RP 一应俱全
1.38.x2024-08Spring Boot 3.x 完整支持——sa-token-spring-boot3-starter 单独发包
1.40.x2025-03JDK 21 虚拟线程适配、JWT 增强(jose4j 升级)
1.42.x2025-08Sa-Token SSO 三模式升级,新增模式四:SSO-IdP 标准 OIDC 接入
1.44.x2026-01前后端分离 OAuth2.0 PKCE 模式、多租户增强(Tenancy 抽象)

关键变化:从 1.36 开始,sa-token 不再只是"权限框架",而是"OAuth2.0 / OIDC 服务端 + 客户端"——可以拿来做完整 IdP 平台。

9.2 2024+ 新模式:模式四 SSO-IdP(OIDC 标准)

2021 年本文介绍了三种 SSO 模式,2025 年 sa-token 新增"模式四"

1
2
3
4
5
6
7
                        IdP 平台
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
   App1 (OIDC RP)      App2 (OIDC RP)      App3 (OIDC RP)
   - 企业自研            - 商业 SaaS          - 第三方系统
   - 用 sa-token         - 用 keycloak       - 用 Auth0

特点

  • 完全兼容 OIDC 规范——任何标准 OIDC 客户端(keycloak / Auth0 / Okta)都能接入
  • Discovery Endpoint/.well-known/openid-configuration)自动暴露 IdP 元信息
  • 支持 PKCE——2024+ 移动互联网标配(防止授权码拦截)
  • JWK 端点/.well-known/jwks.json)——第三方系统可以本地验证 JWT,无需请求 IdP

适用场景:企业自建 IdP 平台,对外开放给第三方应用或 SaaS 系统

9.3 OAuth2.0 实战补充(2024+ 主流用法)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# sa-token 1.38+ 配置 OAuth2.0 服务端
sa-token:
  oauth2:
    # 授权码模式 token 有效期
    code-timeout: 300
    # access_token 有效期
    access-token-timeout: 7200
    # refresh_token 有效期
    refresh-token-timeout: 2592000
    # 是否强制 PKCE(2024+ 强烈建议 true)
    force-pkce: true
    # 客户端列表
    clients:
      - client-id: web-admin
        client-secret: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
        grant-types:
          - authorization_code
          - refresh_token
        scopes:
          - user.read
          - user.write
        redirect-uris:
          - https://admin.example.com/oauth/callback
      - client-id: mobile-app
        # 移动端走 PKCE,不需要 client_secret
        grant-types:
          - authorization_code
        scopes:
          - user.profile
        redirect-uris:
          - com.example.app://oauth/callback
        require-pkce: true

2024+ 主流选择

  • Web 后台 → authorization_code + client_secret
  • 移动 App / SPA → authorization_code + PKCE(不再用 implicit 模式
  • 服务间调用 → client_credentials
  • 老系统对接 → password(已不推荐,2024+ 多数项目禁用

9.4 与 Spring Authorization Server / Keycloak 的对比

维度sa-token OAuth2.0Spring Authorization ServerKeycloak
学习成本极低(中文文档)中(需理解 Spring Security 6)高(独立服务)
部署复杂度嵌入式嵌入式独立进程
OIDC 完整度1.42+ 完整完整完整(业界标杆)
国内合规强(等保 2.0 SM2/SM4 支持)弱(默认算法不符合国密)
生态丰富度国内最活跃国际化国际化
多租户1.44+ 增强
Spring Boot 3.x1.38+ 完整1.2+26+

2024+ 选型经验

  • 国内中小项目:sa-token(最简单 + 中文社区)
  • 企业级合规(金融/政务):sa-token + 国密算法扩展
  • 跨云/跨国大厂:Keycloak / Spring Authorization Server
  • 不想自己运维:Auth0 / Authing(国内)/ 阿里云 IDaaS

9.5 个人回顾:从"单点登录"到"全场景身份中台"

3 年前写这篇文章时,sa-token 还只是"轻量级 Java 权限框架"。2024-2026 它已经演变成"Java 身份中台"

  • 2018-2020:单点登录(SSO)
  • 2020-2022:权限认证 + 微服务网关
  • 2022-2024:OAuth2.0 完整实现
  • 2024-2026:OIDC IdP 平台 + 多租户 + 国密合规

国内 Java 身份认证的"大一统"正在发生——sa-token、Keycloak 都在抢"一站式 IdP"的山头。

如果 2024 年再做 SSO 选型,我会先评估"未来 3 年是否要做 IdP"——是 → sa-token 1.42+ / Keycloak;否 → 单点登录模式二 + 简单 Redis 即可。

参考资料(2024+ 补充)

使用 Hugo 构建
主题 StackJimmy 设计