完善单点登录文档

This commit is contained in:
click33 2021-08-29 23:52:45 +08:00
parent 84679d5fd4
commit 3567e9f54b
7 changed files with 111 additions and 94 deletions

View File

@ -15,12 +15,7 @@ import cn.dev33.satoken.util.SaResult;
@RestController
public class SsoClientController {
/*
* SSO-Client端处理所有SSO相关请求
* http://{host}:{port}/sso/login -- Client端登录地址接受参数back=登录后的跳转地址
* http://{host}:{port}/sso/logout -- Client端单点注销地址isSlo=true时打开接受参数back=注销后的跳转地址
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址isSlo=true时打开此接口为框架回调开发者无需关心
*/
// 首页
@RequestMapping("/")
public String index() {
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
@ -30,7 +25,12 @@ public class SsoClientController {
return str;
}
// SSO-Client端处理所有SSO相关请求
/*
* SSO-Client端处理所有SSO相关请求
* http://{host}:{port}/sso/login -- Client端登录地址接受参数back=登录后的跳转地址
* http://{host}:{port}/sso/logout -- Client端单点注销地址isSlo=true时打开接受参数back=注销后的跳转地址
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址isSlo=true时打开此接口为框架回调开发者无需关心
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
return SaSsoHandle.clientRequest();

View File

@ -6,7 +6,7 @@ server:
sa-token:
# SSO-相关配置
sso:
# SSO-Server端 单点登录地址
# SSO-Server端 统一认证地址
auth-url: http://sa-sso-server.com:9000/sso/auth
# 是否打开单点注销接口
is-slo: true

View File

@ -6,7 +6,7 @@ server:
sa-token:
# SSO-相关配置
sso:
# SSO-Server端 单点登录地址
# SSO-Server端 统一认证地址
auth-url: http://sa-sso-server.com:9000/sso/auth
# 使用Http请求校验ticket
is-http: true

View File

@ -18,8 +18,6 @@
而共享Redis并不需要我们把所有项目的数据都放在同一个Redis中Sa-Token提供了 **[权限缓存与业务缓存分离]** 的解决方案,详情戳:[Alone独立Redis插件](/plugin/alone-redis)。
<!-- > PS这里建议不要用B项目去连接A项目的Redis也不要A项目连接B项目的Redis而是抽离出一个单独的 SSO-RedisA 和 B 一起连接这个 SSO-Redis -->
OK所有理论就绪下面开始实战
> Sa-Token整合同域单点登录非常简单相比于正常的登录你只需增加配置 `sa-token.cookie-domain=xxx.com` 指定一下Cookie写入时的父级域名即可。 <br>
@ -37,7 +35,8 @@ OK所有理论就绪下面开始实战
127.0.0.1 s3.stp.com
```
其中:`sso.stp.com`为统一认证地址,当用户在其它 Client 端发起登录请求时,均将其重定向至认证中心,待到登录成功之后再原路返回到 Client 端。
<!-- 其中:`sso.stp.com`为统一认证地址,当用户在其它 Client 端发起登录请求时,均将其重定向至认证中心,待到登录成功之后再原路返回到 Client 端。 -->
其中:`sso.stp.com`为统一认证地址,其它均为 Client 端。
### 2、指定Cookie的作用域
@ -100,7 +99,7 @@ public class SaSsoApplication {
![sso-type1-wd.png](https://oss.dev33.cn/sa-token/doc/sso/sso-type1-wd.png 's-w-sh')
现在访问任意节点的登录接口:[http://s1.stp.com:8081/sso/doLogin](http://s1.stp.com:8081/sso/doLogin)
现在访问SSO认证中心的登录接口[http://sso.stp.com:8081/sso/doLogin](http://sso.stp.com:8081/sso/doLogin)
![sso-type1-login.png](https://oss.dev33.cn/sa-token/doc/sso/sso-type1-login.png 's-w-sh')
@ -111,11 +110,11 @@ public class SaSsoApplication {
测试完毕!
### 5、搭建统一认证中心
### 5、完善统一认证中心
上面的示例我们简单的演示了SSO模式一的认证原理。
当然,在实际的正式项目中,我们肯定不会每个系统都内置一个登录接口一般的做法是搭建一个独立的SSO认证中心,我们所有 Client 端的登录请求都会被重定向至认证中心,
当然,在实际的正式项目中,我们肯定不会每个 Client 端都内置一个登录接口一般的做法是只在SSO认证中心保留登录接口,我们所有 Client 端的登录请求都会被重定向至认证中心,
待到登录成功之后再原路返回到 Client 端。
我们可以运行一下官方仓库的示例,里面有制作好的登录页面

View File

@ -1,31 +1,34 @@
# SSO模式二 URL重定向传播会话
如果我们的多个系统部署在不同的域名之下但是后端可以连接同一个Redis那么便可以使用 **`[URL重定向传播会话]`** 的方式做到单点登录
如果我们的多个系统部署在不同的域名之下但是后端可以连接同一个Redis那么便可以使用 **`[URL重定向传播会话]`** 的方式做到单点登录
### 0、解题思路
首先我们再次复习一下多个系统之间为什么无法同步登录状态?
首先我们再次复习一下多个系统之间为什么无法同步登录状态?
1. 前端的`Token`无法在多个系统下共享
2. 后端的`Session`无法在多个系统间共享
1. 前端的`Token`无法在多个系统下共享
2. 后端的`Session`无法在多个系统间共享
关于第二点,我们已在"SSO模式一"章节中阐述,使用 [Alone独立Redis插件](/plugin/alone-redis) 做到权限缓存直连SSO-Redis数据中心在此不再赘述
关于第二点,我们已在 "SSO模式一" 章节中阐述,使用 [Alone独立Redis插件](/plugin/alone-redis) 做到权限缓存直连 SSO-Redis 数据中心,在此不再赘述
而第一点,才是我们解决问题的关键所在,在跨域模式下,意味着"共享Cookie方案"的失效我们必须采用一种新的方案来传递Token
而第一点,才是我们解决问题的关键所在,在跨域模式下,意味着 "共享Cookie方案" 的失效我们必须采用一种新的方案来传递Token
1. 用户在 子系统 点击`[登录]`按钮
2. 用户跳转到子系统登录页面,并携带`back参数`记录初始页面URL
3. 子系统检测到此用户尚未登录再次将其重定向至SSO认证中心并携带`redirect参数`记录子系统的登录页URL
4. 用户在SSO认证中心尚未登录开始登录
5. 用户在SSO认证中心登录成功重定向至子系统的登录页URL并携带`ticket码`
6. 子系统使用ticket码从`SSO-Redis`中获取账号id并在子系统登录此账号会话
7. 子系统将用户再次重定向至最初始的`back`页面
1. 用户在 子系统 点击 `[登录]` 按钮。
2. 用户跳转到子系统登录接口 `/sso/login`,并携带 `back参数` 记录初始页面URL。
- 形如:`http://{sso-client}/sso/login?back=xxx`
3. 子系统检测到此用户尚未登录再次将其重定向至SSO认证中心并携带`redirect参数`记录子系统的登录页URL。
- 形如:`http://{sso-server}/sso/auth?redirect=xxx?back=xxx`
4. 用户进入了 SSO认证中心 的登录页面,开始登录。
5. 用户 输入账号密码 并 登录成功SSO认证中心再次将用户重定向至子系统的登录接口`/sso/login`,并携带`ticket码`参数。
- 形如:`http://{sso-client}/sso/login?back=xxx&ticket=xxxxxxxxx`
6. 子系统根据 `ticket码``SSO-Redis` 中获取账号id并在子系统登录此账号会话。
7. 子系统将用户再次重定向至最初始的 `back` 页面。
整个过程除了第四步用户在SSO认证中心登录时会被打断其余过程均是自动化的当用户在另一个子系统再次点击`[登录]`按钮由于此用户在SSO认证中心已有会话登录
整个过程除了第四步用户在SSO认证中心登录时会被打断其余过程均是自动化的当用户在另一个子系统再次点击`[登录]`按钮由于此用户在SSO认证中心已有会话存在
所以第四步也将自动化,也就是单点登录的最终目的 —— 一次登录,处处通行。
下面我们按照步骤依次完成上述过程
下面我们按照步骤依次完成上述过程
### 1、准备工作
首先修改hosts文件`(C:\windows\system32\drivers\etc\hosts)`添加以下IP映射方便我们进行测试
@ -37,12 +40,12 @@
```
### 2、搭建SSO-Server认证中心
### 2、搭建 SSO-Server 认证中心
> 搭建示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso2-server/`,如遇到难点可结合源码进行测试学习
##### 2.1、创建SSO-Server端项目
创建SpringBoot项目 `sa-token-demo-sso-server`不会的同学自行百度或参考仓库示例添加pom依赖:
#### 2.1、创建 SSO-Server 端项目
创建 SpringBoot 项目 `sa-token-demo-sso-server`,引入依赖:
``` xml
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
@ -52,7 +55,7 @@
<version>${sa.top.version}</version>
</dependency>
<!-- Sa-Token整合redis (使用jackson序列化方式) -->
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
@ -64,7 +67,14 @@
</dependency>
```
##### 2.2、创建SSO-Server端认证接口
#### 2.2、开放认证接口
一个完整的SSO认证中心应该至少包含以下接口
- `/sso/auth`:单点登录统一认证地址。
- `/sso/doLogin`RestAPI 登录接口,根据账号密码进行登录。
- `/sso/logout`:统一单点注销地址,一次注销,全端下线。
别急,这里不需要你亲自完成这些接口 —— Sa-Token 已经为你封装了实现。你要做的,就是提供一个访问入口,接入 Sa-Token 的方法。
``` java
/**
* Sa-Token-SSO Server端 Controller
@ -111,7 +121,7 @@ public class SsoServerController {
```
注意:在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数可通过`SaHolder.getRequest().getParam("xxx")`来获取
##### 2.3、application.yml配置
#### 2.3、application.yml配置
``` yml
# 端口
server:
@ -140,7 +150,7 @@ spring:
```
注意点:`allow-url`为了方便测试配置为`*`线上生产环境一定要配置为详细URL地址 (之后的章节我们会详细阐述此配置项)
##### 2.4、创建SSO-Server端启动类
#### 2.4、创建SSO-Server端启动类
``` java
@SpringBootApplication
public class SaSsoServerApplication {
@ -152,12 +162,12 @@ public class SaSsoServerApplication {
```
### 3、搭建SSO-Client应用端
### 3、搭建 SSO-Client 应用端
> 搭建示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso2-client/`,如遇到难点可结合源码进行测试学习
##### 3.1、创建SSO-Client端项目
创建一个SpringBoot项目 `sa-token-demo-sso-client`添加pom依赖:
#### 3.1、创建SSO-Client端项目
创建一个 SpringBoot 项目 `sa-token-demo-sso-client`,引入依赖:
``` xml
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
@ -186,7 +196,10 @@ public class SaSsoServerApplication {
```
##### 3.2、创建SSO-Client端认证接口
#### 3.2、创建 SSO-Client 端认证接口
同 SSO-Server 一样Sa-Token 为 SSO-Client 端所需代码也提供了完整的封装,你只需提供一个访问入口,接入 Sa-Token 的方法即可。
``` java
/**
@ -195,12 +208,7 @@ public class SaSsoServerApplication {
@RestController
public class SsoClientController {
/*
* SSO-Client端处理所有SSO相关请求
* http://{host}:{port}/sso/login -- Client端登录地址接受参数back=登录后的跳转地址
* http://{host}:{port}/sso/logout -- Client端单点注销地址isSlo=true时打开接受参数back=注销后的跳转地址
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址isSlo=true时打开此接口为框架回调开发者无需关心
*/
// 首页
@RequestMapping("/")
public String index() {
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
@ -210,7 +218,12 @@ public class SsoClientController {
return str;
}
// SSO-Client端处理所有SSO相关请求
/*
* SSO-Client端处理所有SSO相关请求
* http://{host}:{port}/sso/login -- Client端登录地址接受参数back=登录后的跳转地址
* http://{host}:{port}/sso/logout -- Client端单点注销地址isSlo=true时打开接受参数back=注销后的跳转地址
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址isSlo=true时打开此接口为框架回调开发者无需关心
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
return SaSsoHandle.clientRequest();
@ -230,7 +243,7 @@ server:
sa-token:
# SSO-相关配置
sso:
# SSO-Server端 单点登录地址
# SSO-Server端 统一认证地址
auth-url: http://sa-sso-server.com:9000/sso/auth
# 是否打开单点注销接口
is-slo: true
@ -248,7 +261,7 @@ sa-token:
```
注意点:`sa-token.alone-redis` 的配置需要和SSO-Server端连接同一个Redisdatabase也要一样
##### 3.4、写启动类
#### 3.4、写启动类
``` java
@SpringBootApplication
public class SaSsoClientApplication {
@ -263,7 +276,7 @@ public class SaSsoClientApplication {
### 4、测试访问
(1) 依次启动SSO-Server与SSO-Client端,然后从浏览器访问:[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
(1) 依次启动 `SSO-Server``SSO-Client`,然后从浏览器访问:[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
![sso-client-index.png](https://oss.dev33.cn/sa-token/doc/sso/sso-client-index.png 's-w-sh')

View File

@ -6,25 +6,27 @@
### 0、问题分析
我们先来分析一下,当后端不使用共享Redis时会对架构产生哪些影响
我们先来分析一下,当后端不使用共享 Redis 时,会对架构产生哪些影响:
1. Client端 无法直连 Redis 校验 ticket取出账号id
2. Client 无法与 Server 共用一套会话,需要自行维护子会话
3. 由于不是一套会话,所以无法“一次注销,全端下线”,需要额外编写代码完成单点注销
1. Client 端无法直连 Redis 校验 ticket取出账号id。
2. Client 无法与 Server 共用一套会话,需要自行维护子会话
3. 由于不是一套会话,所以无法“一次注销,全端下线”,需要额外编写代码完成单点注销
所以模式三的主要目标:也就是在 模式二的基础上 解决上述 三个难题
> 模式三的Demo示例地址<br/>
> SSO-Server端 `/sa-token-demo/sa-token-demo-sso3-server/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-sso3-server) <br/>
> SSO-Client端 `/sa-token-demo/sa-token-demo-sso3-client/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-sso3-client) <br/>
> 模式三的 Demo 示例地址:
>
> - SSO-Server 端:`/sa-token-demo/sa-token-demo-sso3-server/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-sso3-server) <br/>
> - SSO-Client 端:`/sa-token-demo/sa-token-demo-sso3-client/` [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-sso3-client) <br/>
>
> 如遇难点可参考示例
### 1、SSO-Server认证中心开放ticket校验接口
既然Client端无法直连Redis校验ticket那就在Server端开放ticket校验接口然后Client端通过http请求获取数据
### 1、SSO-Server 认证中心开放 Ticket 校验接口
既然 Client 端无法直连 Redis 校验 Ticket那我们就在 Server 端开放 Ticket 校验接口,然后 Client 端通过 http 请求获取数据。
##### 1.1、添加依赖
首先在Server端和Client端均添加以下依赖如果不需要单点注销功能则Server端可不引入
#### 1.1、添加依赖
首先在 Server 端和 Client 端均添加以下依赖(如果不需要单点注销功能则 Server 端可不引入)
``` xml
<!-- Http请求工具 -->
<dependency>
@ -35,8 +37,8 @@
```
> OkHttps是一个轻量级http请求工具详情参考[OkHttps](https://gitee.com/ejlchina-zhxu/okhttps)
##### 1.2、认证中心开放接口
在SSO-Server端的`application.yml`中,新增以下配置:
#### 1.2、认证中心开放接口
SSO-Server 端的 `application.yml` 中,新增以下配置:
``` yml
sa-token:
sso:
@ -45,14 +47,14 @@ sa-token:
```
此配置项的作用是开放ticket校验接口让Client端通过http请求获取会话
##### 1.3、Client端新增配置
在SSO-Client端的`SsoClientController`中,新增以下配置
#### 1.3、Client端新增配置
在SSO-Client端的 `SsoClientController` 中,新增以下配置
``` java
// 配置SSO相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
cfg.sso
// 配置Http请求处理器
// 配置 Http 请求处理器
.setSendHttp(url -> {
return OkHttps.sync(url).get().getBody().toString();
})
@ -69,15 +71,15 @@ sa-token:
check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket
```
##### 1.5 启动项目测试
#### 1.4、启动项目测试
启动SSO-Server、SSO-Client访问测试[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
> 注如果已测试运行模式二可先将Redis中的数据清空以防旧数据对测试造成干扰
### 2、获取Userinfo
### 2、获取 Userinfo
除了账号id我们可能还需要将用户的昵称、头像等信息从 Server端 带到 Client端用户资料的同步。要解决这个需求我们只需
##### 2.1、在Server端自定义接口查询用户资料
#### 2.1、在 Server 端自定义接口,查询用户资料
``` java
// 自定义接口获取userinfo
@RequestMapping("/sso/userinfo")
@ -96,7 +98,7 @@ public Object userinfo(String loginId, String secretkey) {
}
```
##### 2.2、在Client端调用此接口查询userinfo
#### 2.2、在 Client 端调用此接口查询 userinfo
首先在yml中配置接口地址
``` yml
sa-token:
@ -124,16 +126,18 @@ public Object myinfo() {
有了单点登录就必然要有单点注销网上给出的大多数解决方案是将注销请求重定向至SSO-Server中心逐个通知Client端下线
在某些场景下页面的跳转可能造成不太好的用户体验Sa-Token-SSO 允许你以 `REST API` 的形式构建接口,做到页面无刷新单点注销
在某些场景下页面的跳转可能造成不太好的用户体验Sa-Token-SSO 允许你以 `REST API` 的形式构建接口,做到页面无刷新单点注销
1. Client端校验ticket的时候将注销回调地址发送到Server端
2. Server端将注销回调地址存储到Set集合
3. Client端向Server端发送单点注销请求
4. Server端遍历Set集合逐个通知Client端下线
5. Server端注销下线
6. 单点注销完成
1. Client 端在校验 ticket 时,将注销回调地址发送到 Server 端。
2. Server 端将此 Client 的注销回调地址存储到 Set 集合
3. Client 端向 Server 端发送单点注销请求
4. Server 端遍历Set集合逐个通知 Client 端下线
5. Server 端注销下线
6. 单点注销完成
##### 2.1、SSO-Server认证中心增加配置
这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文章增加以下配置即可:
#### 2.1、SSO-Server认证中心增加配置
`SsoServerController` 中新增配置
``` java
// 配置SSO相关参数
@ -160,9 +164,9 @@ sa-token:
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
##### 2.2、SSO-Client端新增配置
#### 2.2、SSO-Client 端新增配置
`application.yml` 增加配置:`API调用秘钥` 和 `单点注销接口URL`
`application.yml` 增加配置:`API调用秘钥` 和 `单点注销接口URL`
``` yml
sa-token:
sso:
@ -174,21 +178,21 @@ sa-token:
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
##### 2.3 启动测试
#### 2.3 启动测试
启动SSO-Server、SSO-Client访问测试[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
我们主要的测试点在于 `单点注销`,正常登陆即可
我们主要的测试点在于 `单点注销`,正常登录即可。
![sso-type3-client-index.png](https://oss.dev33.cn/sa-token/doc/sso/sso-type3-client-index.png 's-w-sh')
点击 **`[注销]`** 按钮,即可单点注销成功
点击 **`[注销]`** 按钮,即可单点注销成功
<!-- ![sso-type3-slo.png](https://oss.dev33.cn/sa-token/doc/sso/sso-type3-slo.png 's-w-sh') -->
![sso-type3-slo-index.png](https://oss.dev33.cn/sa-token/doc/sso/sso-type3-slo-index.png 's-w-sh')
PS这里我们为了方便演示使用的是超链接跳页面的形式正式项目中使用Ajax调用接口即可做到无刷单点登录退出
PS这里我们为了方便演示使用的是超链接跳页面的形式正式项目中使用 Ajax 调用接口即可做到无刷单点登录退出
例如我们使用 [APIPost接口测试工具](https://www.apipost.cn/) 可以做到同样的效果:
例如我们使用 [APIPost接口测试工具](https://www.apipost.cn/) 可以做到同样的效果:
![sso-slo-apipost.png](https://oss.dev33.cn/sa-token/doc/sso/sso-slo-apipost.png 's-w-sh')
@ -198,13 +202,13 @@ PS这里我们为了方便演示使用的是超链接跳页面的形式
### 4、后记
当我们熟读三种模式的单点登录之后,其实不难发现:所谓单点登录,其本质就是多个系统之间的会话共享
当我们熟读三种模式的单点登录之后,其实不难发现:所谓单点登录,其本质就是多个系统之间的会话共享
当我们理解这一点之后,三种模式的工作原理也浮出水面:
- 模式一采用共享Cookie来做到前端Token的共享从而达到后端的Session会话共享
- 模式二采用URL重定向以ticket码为授权中介做到多个系统间的会话传播
- 模式三:采用Http请求主动查询会话做到Client端与Server端的会话同步
- 模式一:采用共享 Cookie 来做到前端 Token 的共享,从而达到后端的 Session 会话共享
- 模式二:采用 URL 重定向,以 ticket 码为授权中介,做到多个系统间的会话传播
- 模式三:采用 Http 请求主动查询会话,做到 Client 端与 Server 端的会话同步。

View File

@ -82,10 +82,11 @@ spring:
**3. 集成Redis后是我额外手动保存数据还是框架自动保存** <br>
框架自动保存。集成`Redis`只需要引入对应的`pom依赖`即可框架所有上层API保持不变
**4. 集成包版本问题** <br>
Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题
<br><br>
更多框架的集成方案正在更新中... (欢迎大家提交pr)
更多框架的集成方案正在更新中...
!> 注意: 集成sa-token-dao-redis的版本需要与sa-token启动依赖版本保持一致, 否则可能会报错(在低版本依赖里面找不到高版本的方法)