diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java
index b898ed83..1d2c46d2 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java
@@ -1,5 +1,6 @@
package com.pj;
+import cn.dev33.satoken.sso.SaSsoManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -8,7 +9,11 @@ public class SaSsoServerApplication {
public static void main(String[] args) {
SpringApplication.run(SaSsoServerApplication.class, args);
- System.out.println("\n------ Sa-Token-SSO 统一认证中心启动成功 ");
+
+ System.out.println();
+ System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
+ System.out.println("配置信息:" + SaSsoManager.getServerConfig());
+ System.out.println();
}
}
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java
index 7302afd7..6e2e64ee 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java
@@ -25,7 +25,7 @@ public class SsoServerController {
* http://{host}:{port}/sso/auth -- 单点登录授权地址,接受参数:redirect=授权重定向地址
* http://{host}:{port}/sso/doLogin -- 账号密码登录接口,接受参数:name、pwd
* http://{host}:{port}/sso/checkTicket -- Ticket校验接口(isHttp=true时打开),接受参数:ticket=ticket码、ssoLogoutCall=单点注销回调地址 [可选]
- * http://{host}:{port}/sso/signout -- 单点注销地址(isSlo=true时打开),接受参数:loginId=账号id、secretkey=接口调用秘钥
+ * http://{host}:{port}/sso/signout -- 单点注销地址(isSlo=true时打开),接受参数:loginId=账号id、sign=参数签名
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/pom.xml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/pom.xml
index 513629c2..e2599ed8 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/pom.xml
@@ -60,7 +60,14 @@
sa-token-alone-redis
${sa-token.version}
-
+
+
+
+ com.dtflys.forest
+ forest-spring-boot-starter
+ 1.5.26
+
+
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/sso/SsoClientController.java
index 11383970..4eeed193 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/sso/SsoClientController.java
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/java/com/pj/sso/SsoClientController.java
@@ -1,8 +1,11 @@
package com.pj.sso;
+import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
+import com.dtflys.forest.Forest;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -35,6 +38,18 @@ public class SsoClientController {
return SaSsoClientProcessor.instance.dister();
}
+ // 配置SSO相关参数
+ @Autowired
+ private void configSso(SaSsoClientConfig ssoClient) {
+ // 配置Http请求处理器
+ ssoClient.sendHttp = url -> {
+ System.out.println("------ 发起请求:" + url);
+ String resStr = Forest.get(url).executeAsString();
+ System.out.println("------ 请求结果:" + resStr);
+ return resStr;
+ };
+ }
+
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml
index f971cae7..8ce56dd6 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/src/main/resources/application.yml
@@ -4,14 +4,15 @@ server:
# sa-token配置
sa-token:
- # 每次登录时,产生不同的token
- is-share: false
# SSO-相关配置
sso-client:
- # SSO-Server端 统一认证地址
+ # SSO-Server 端主机地址
server-url: http://sa-sso-server.com:9000
# 前后端分离时用这个
# auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
alone-redis:
@@ -35,8 +36,7 @@ sa-token:
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 0
-
-
-
-
-
\ No newline at end of file
+
+forest:
+ # 关闭 forest 请求日志打印
+ log-enabled: false
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/.gitignore b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/.gitignore
new file mode 100644
index 00000000..99a6e767
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/.gitignore
@@ -0,0 +1,12 @@
+target/
+
+node_modules/
+bin/
+.settings/
+unpackage/
+.classpath
+.project
+
+.idea/
+
+.factorypath
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/pom.xml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/pom.xml
new file mode 100644
index 00000000..cd61b769
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/pom.xml
@@ -0,0 +1,68 @@
+
+ 4.0.0
+ cn.dev33
+ sa-token-demo-sso3-client-test2
+ 0.0.1-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.5.14
+
+
+
+
+
+ 1.37.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ cn.dev33
+ sa-token-spring-boot-starter
+ ${sa-token.version}
+
+
+
+
+ cn.dev33
+ sa-token-sso
+ ${sa-token.version}
+
+
+
+
+ cn.dev33
+ sa-token-redis-jackson
+ ${sa-token.version}
+
+
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+
+ com.dtflys.forest
+ forest-spring-boot-starter
+ 1.5.26
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/SaSso3ClientTest2Application.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/SaSso3ClientTest2Application.java
new file mode 100644
index 00000000..1374e3b7
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/SaSso3ClientTest2Application.java
@@ -0,0 +1,23 @@
+package com.pj;
+
+import cn.dev33.satoken.sso.SaSsoManager;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SaSso3ClientTest2Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SaSso3ClientTest2Application.class, args);
+
+ System.out.println();
+ System.out.println("---------------------- Sa-Token SSO 模式三 Client 端启动成功 ----------------------");
+ System.out.println("配置信息:" + SaSsoManager.getClientConfig());
+ System.out.println("测试访问应用端一: http://sa-sso-client1.com:9032");
+ System.out.println("测试访问应用端二: http://sa-sso-client2.com:9032");
+ System.out.println("测试访问应用端三: http://sa-sso-client3.com:9032");
+ System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
+ System.out.println();
+ }
+
+}
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/sso/SsoClientController.java
new file mode 100644
index 00000000..2492688a
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/java/com/pj/sso/SsoClientController.java
@@ -0,0 +1,78 @@
+package com.pj.sso;
+
+import cn.dev33.satoken.sso.config.SaSsoClientConfig;
+import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
+import cn.dev33.satoken.sso.template.SaSsoUtil;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+import com.dtflys.forest.Forest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Sa-Token-SSO Client端 Controller
+ * @author click33
+ */
+@RestController
+public class SsoClientController {
+
+ // SSO-Client端:首页
+ @RequestMapping("/")
+ public String index() {
+ String str = "
Sa-Token SSO-Client 应用端
" +
+ "当前会话是否登录:" + StpUtil.isLogin() + "
" +
+ "登录" +
+ " 注销
";
+ return str;
+ }
+
+ /*
+ * 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 SaSsoClientProcessor.instance.dister();
+ }
+
+ // 配置SSO相关参数
+ @Autowired
+ private void configSso(SaSsoClientConfig ssoClient) {
+ // 配置Http请求处理器
+ ssoClient.sendHttp = url -> {
+ System.out.println("------ 发起请求:" + url);
+ String resStr = Forest.get(url).executeAsString();
+ System.out.println("------ 请求结果:" + resStr);
+ return resStr;
+ };
+ }
+
+ // 查询我的账号信息
+ @RequestMapping("/sso/myInfo")
+ public Object myInfo() {
+ // 组织请求参数
+ Map map = new HashMap<>();
+ map.put("apiType", "userinfo");
+ map.put("loginId", StpUtil.getLoginId());
+
+ // 发起请求
+ Object resData = SaSsoUtil.getData(map);
+ System.out.println("sso-server 返回的信息:" + resData);
+ return resData;
+ }
+
+ // 全局异常拦截
+ @ExceptionHandler
+ public SaResult handlerException(Exception e) {
+ e.printStackTrace();
+ return SaResult.error(e.getMessage());
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/resources/application.yml
new file mode 100644
index 00000000..ebec4dde
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client-test2/src/main/resources/application.yml
@@ -0,0 +1,49 @@
+# 端口
+server:
+ port: 9032
+
+# sa-token配置
+sa-token:
+ # sso-client 相关配置
+ sso-client:
+ # client 标识
+ client: sso-client3-test2
+ # sso-server 端主机地址
+ server-url: http://sa-sso-server.com:9000
+ # 使用 Http 请求校验ticket (模式三)
+ is-http: true
+
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+
+spring:
+ # 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
+ redis:
+ # Redis数据库索引
+ database: 4
+ # Redis服务器地址
+ host: 127.0.0.1
+ # Redis服务器连接端口
+ port: 6379
+ # Redis服务器连接密码(默认为空)
+ password:
+ # 连接超时时间
+ timeout: 10s
+ lettuce:
+ pool:
+ # 连接池最大连接数
+ max-active: 200
+ # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: -1ms
+ # 连接池中的最大空闲连接
+ max-idle: 10
+ # 连接池中的最小空闲连接
+ min-idle: 0
+
+forest:
+ # 关闭 forest 请求日志打印
+ log-enabled: false
+
+
+
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml
index f1bce7e4..ef48e853 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml
@@ -6,6 +6,8 @@ server:
sa-token:
# sso-client 相关配置
sso-client:
+ # client 标识
+ client: sso-client3
# sso-server 端主机地址
server-url: http://sa-sso-server.com:9000
# 使用 Http 请求校验ticket (模式三)
@@ -19,7 +21,7 @@ spring:
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
redis:
# Redis数据库索引
- database: 2
+ database: 3
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
diff --git a/sa-token-doc/sso/sso-apidoc.md b/sa-token-doc/sso/sso-apidoc.md
index 8cb487b2..14d29257 100644
--- a/sa-token-doc/sso/sso-apidoc.md
+++ b/sa-token-doc/sso/sso-apidoc.md
@@ -22,6 +22,7 @@ http://{host}:{port}/sso/auth
| :-------- | :-------- | :-------- |
| redirect | 是 | 登录成功后的重定向地址,一般填写 location.href(从哪来回哪去) |
| mode | 否 | 授权模式,取值 [simple, ticket],simple=登录后直接重定向,ticket=带着ticket参数重定向,默认值为ticket |
+| client | 否 | 客户端标识,可不填,代表是一个匿名应用,若填写了,则校验 ticket 时也必须时这个 client 才可以校验成功 |
访问接口后有两种情况:
- 情况一:当前会话在 SSO 认证中心未登录,会进入登录页开始登录。
@@ -40,7 +41,7 @@ http://{host}:{port}/sso/doLogin
| name | 是 | 用户名 |
| pwd | 是 | 密码 |
-此接口属于 RestAPI (使用ajax访问),会进入后端配置的 `sso.setDoLoginHandle` 函数中,此函数的返回值即是此接口的响应值。
+此接口属于 RestAPI (使用ajax访问),会进入后端配置的 `ssoServer.doLoginHandle` 函数中,此函数的返回值即是此接口的响应值。
另外需要注意:此接口并非只能携带 name、pwd 参数,因为你可以在方法里通过 `SaHolder.getRequest().getParam("xxx")` 来获取前端提交的其它参数。
@@ -58,6 +59,7 @@ http://{host}:{port}/sso/checkTicket
| :-------- | :-------- | :-------- |
| ticket | 是 | 在步骤 1 中授权重定向时的 ticket 参数 |
| ssoLogoutCall | 否 | 单点注销时的回调通知地址,只在SSO模式三单点注销时需要携带此参数|
+| client | 否 | 客户端标识,可不填,代表是一个匿名应用,若填写了,则必须填写的和 `/sso/auth` 登录时填写的一致才可以校验成功 |
返回值场景:
- 校验成功时:
@@ -106,6 +108,7 @@ http://{host}:{port}/sso/signout?back=xxx
| timestamp | 是 | 当前时间戳,13位 |
| nonce | 是 | 随机字符串 |
| sign | 是 | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}×tamp={13位时间戳}&key={secretkey秘钥} )` |
+| client | 否 | 客户端标识,可不填,一般在帮助 “sso-server 端不同client不同秘钥” 的场景下找到对应秘钥时,才填写 |
例如:
``` url
@@ -198,7 +201,8 @@ http://{host}:{port}/sso/logoutCall
| loginId | 是 | 要注销的账号 id |
| timestamp | 是 | 当前时间戳,13位 |
| nonce | 是 | 随机字符串 |
-| sign | 是 | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}×tamp={13位时间戳}&key={secretkey秘钥} )` |
+| client | 否 | 客户端标识,如果你在登录时向 sso-server 端传递了 client 值,那么在此处 sso-server 也会给你回传过来,否则此参数无值 |
+| sign | 是 | 签名,生成算法:`md5( loginId={账号id}&nonce={随机字符串}×tamp={13位时间戳}&key={secretkey秘钥} )` 如果 client 参数有值,则client也要参与签名,放在 loginId 参数签名(字典顺序)|
返回数据:
diff --git a/sa-token-doc/sso/sso-server.md b/sa-token-doc/sso/sso-server.md
index b87084ab..9193a8ab 100644
--- a/sa-token-doc/sso/sso-server.md
+++ b/sa-token-doc/sso/sso-server.md
@@ -90,21 +90,21 @@ implementation 'com.dtflys.forest:forest-spring-boot-starter:1.5.26'
@RestController
public class SsoServerController {
- /*
+ /**
* SSO-Server端:处理所有SSO相关请求 (下面的章节我们会详细列出开放的接口)
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
- return SaSsoProcessor.instance.serverDister();
+ return SaSsoServerProcessor.instance.dister();
}
/**
* 配置SSO相关参数
*/
@Autowired
- private void configSso(SaSsoConfig sso) {
+ private void configSso(SaSsoServerConfig ssoServer) {
// 配置:未登录时返回的View
- sso.notLoginView = () -> {
+ ssoServer.notLoginView = () -> {
String msg = "当前会话在SSO-Server端尚未登录,请先访问"
+ " doLogin登录 "
+ "进行登录之后,刷新页面开始授权";
@@ -112,7 +112,7 @@ public class SsoServerController {
};
// 配置:登录处理函数
- sso.doLoginHandle = (name, pwd) -> {
+ ssoServer.doLoginHandle = (name, pwd) -> {
// 此处仅做模拟登录,真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
@@ -122,11 +122,12 @@ public class SsoServerController {
};
// 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉)
- sso.sendHttp = url -> {
+ ssoServer.sendHttp = url -> {
try {
- // 发起 http 请求
System.out.println("------ 发起请求:" + url);
- return Forest.get(url).executeAsString();
+ String resStr = Forest.get(url).executeAsString();
+ System.out.println("------ 请求结果:" + resStr);
+ return resStr;
} catch (Exception e) {
e.printStackTrace();
return null;
@@ -138,8 +139,8 @@ public class SsoServerController {
```
注意:
-- 在`setDoLoginHandle`函数里如果要获取name, pwd以外的参数,可通过`SaHolder.getRequest().getParam("xxx")`来获取
-- 在 `setSendHttp` 函数中,使用 `try-catch` 是为了提高整个注销流程的容错性,避免在一些极端情况下注销失败(例如:某个 Client 端上线之后又下线,导致 http 请求无法调用成功,从而阻断了整个注销流程)
+- 在`doLoginHandle`函数里如果要获取name, pwd以外的参数,可通过`SaHolder.getRequest().getParam("xxx")`来获取
+- 在 `sendHttp` 函数中,使用 `try-catch` 是为了提高整个注销流程的容错性,避免在一些极端情况下注销失败(例如:某个 Client 端上线之后又下线,导致 http 请求无法调用成功,从而阻断了整个注销流程)
全局异常处理:
``` java
@@ -173,7 +174,7 @@ sa-token:
# domain: stp.com
# ------- SSO-模式二相关配置
- sso:
+ sso-server:
# Ticket有效期 (单位: 秒),默认五分钟
ticket-timeout: 300
# 所有允许的授权回调地址
@@ -215,13 +216,13 @@ server.port=9000
# ------- SSO-模式二相关配置
# Ticket有效期 (单位: 秒),默认五分钟
-sa-token.sso.ticket-timeout=300
+sa-token.sso-server.ticket-timeout=300
# 所有允许的授权回调地址
-sa-token.sso.allow-url=*
+sa-token.sso-server.allow-url=*
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
-sa-token.sso.is-http=true
+sa-token.sso-server.is-http=true
# API 接口调用秘钥
sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
@@ -243,7 +244,7 @@ forest.log-enabled: false
-注意点:`sa-token.sso.allow-url`为了方便测试配置为`*`,线上生产环境一定要配置为详细URL地址 (之后的章节我们会详细阐述此配置项)
+注意点:`sa-token.sso-server.allow-url`为了方便测试配置为`*`,线上生产环境一定要配置为详细URL地址 (之后的章节我们会详细阐述此配置项)
### 4、创建启动类
@@ -252,7 +253,11 @@ forest.log-enabled: false
public class SaSsoServerApplication {
public static void main(String[] args) {
SpringApplication.run(SaSsoServerApplication.class, args);
- System.out.println("\n------ Sa-Token-SSO 认证中心启动成功");
+
+ System.out.println();
+ System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
+ System.out.println("配置信息:" + SaSsoManager.getServerConfig());
+ System.out.println();
}
}
```
@@ -261,7 +266,7 @@ public class SaSsoServerApplication {

-访问统一授权地址(仅测试SSO Server部署是否成功访问localhost,测试SSO模式一到模式三建议按照对应文档的域名进行配置并访问):
+访问统一授权地址(仅测试 SSO-Server 是否部署成功,暂时还不需要点击登录):
- [http://localhost:9000/sso/auth](http://localhost:9000/sso/auth)

diff --git a/sa-token-doc/sso/sso-type1.md b/sa-token-doc/sso/sso-type1.md
index f5e59fa7..2bac82ca 100644
--- a/sa-token-doc/sso/sso-type1.md
+++ b/sa-token-doc/sso/sso-type1.md
@@ -135,8 +135,8 @@ public class SsoClientController {
// SSO-Client端:首页
@RequestMapping("/")
public String index() {
- String authUrl = SaSsoManager.getConfig().splicingAuthUrl();
- String solUrl = SaSsoManager.getConfig().splicingSloUrl();
+ String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
+ String solUrl = SaSsoManager.getClientConfig().splicingSloUrl();
String str = "Sa-Token SSO-Client 应用端
" +
"当前会话是否登录:" + StpUtil.isLogin() + "
" +
"登录 " +
@@ -166,11 +166,9 @@ server:
# Sa-Token 配置
sa-token:
# SSO-相关配置
- sso:
- # SSO-Server端-单点登录授权地址
- auth-url: http://sso.stp.com:9000/sso/auth
- # SSO-Server端-单点注销地址
- slo-url: http://sso.stp.com:9000/sso/signout
+ sso-client:
+ # SSO-Server端主机地址
+ server-url: http://sso.stp.com:9000
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
alone-redis:
@@ -192,10 +190,8 @@ server.port=9001
######### Sa-Token 配置 #########
-# SSO-Server端-单点登录授权地址
-sa-token.sso.auth-url=http://sso.stp.com:9000/sso/auth
-# SSO-Server端-单点注销地址
-sa-token.sso.slo-url=http://sso.stp.com:9000/sso/signout
+# SSO-Server端主机地址
+sa-token.sso-client.server-url=http://sso.stp.com:9000
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
# Redis数据库索引
@@ -222,7 +218,15 @@ sa-token.alone-redis.timeout=10s
public class SaSso1ClientApplication {
public static void main(String[] args) {
SpringApplication.run(SaSso1ClientApplication.class, args);
- System.out.println("\nSa-Token SSO模式一 Client端启动成功");
+
+ System.out.println();
+ System.out.println("---------------------- Sa-Token SSO 模式一 Client 端启动成功 ----------------------");
+ System.out.println("配置信息:" + SaSsoManager.getClientConfig());
+ System.out.println("测试访问应用端一: http://s1.stp.com:9001");
+ System.out.println("测试访问应用端二: http://s2.stp.com:9001");
+ System.out.println("测试访问应用端三: http://s3.stp.com:9001");
+ System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
+ System.out.println();
}
}
```
diff --git a/sa-token-doc/sso/sso-type2.md b/sa-token-doc/sso/sso-type2.md
index 4ebe1e87..32d115ea 100644
--- a/sa-token-doc/sso/sso-type2.md
+++ b/sa-token-doc/sso/sso-type2.md
@@ -64,7 +64,7 @@ sa-token.cookie.domain=stp.com
```
-此为模式一专属配置,现在我们将其注释掉
+此为模式一专属配置,现在我们将其注释掉**(一定要注释掉!)**
#### 3.2、创建 SSO-Client 端项目
@@ -151,7 +151,7 @@ public class SsoClientController {
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
- return SaSsoProcessor.instance.clientDister();
+ return SaSsoClientProcessor.instance.dister();
}
}
@@ -170,9 +170,9 @@ server:
# sa-token配置
sa-token:
# SSO-相关配置
- sso:
- # SSO-Server端 统一认证地址
- auth-url: http://sa-sso-server.com:9000/sso/auth
+ sso-client:
+ # SSO-Server 端主机地址
+ server-url: http://sa-sso-server.com:9000
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
alone-redis:
@@ -194,7 +194,7 @@ server.port=9001
######### Sa-Token 配置 #########
# SSO-Server端 统一认证地址
-sa-token.sso.auth-url=http://sa-sso-server.com:9000/sso/auth
+sa-token.sso-client.server-url=http://sa-sso-server.com:9000
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
# Redis数据库索引
@@ -211,7 +211,7 @@ sa-token.alone-redis.timeout=10s
-注意点:`sa-token.alone-redis` 的配置需要和SSO-Server端连接同一个Redis(database也要一样)
+注意点:`sa-token.alone-redis` 的配置需要和SSO-Server端连接同一个Redis**(database 值也要一样!database 值也要一样!database 值也要一样!重说三!)**
#### 3.5、写启动类
``` java
@@ -219,7 +219,15 @@ sa-token.alone-redis.timeout=10s
public class SaSso2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(SaSso2ClientApplication.class, args);
- System.out.println("\nSa-Token-SSO Client端启动成功");
+
+ System.out.println();
+ System.out.println("---------------------- Sa-Token SSO 模式二 Client 端启动成功 ----------------------");
+ System.out.println("配置信息:" + SaSsoManager.getClientConfig());
+ System.out.println("测试访问应用端一: http://sa-sso-client1.com:9001");
+ System.out.println("测试访问应用端二: http://sa-sso-client2.com:9001");
+ System.out.println("测试访问应用端三: http://sa-sso-client3.com:9001");
+ System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
+ System.out.println();
}
}
```
@@ -230,6 +238,8 @@ public class SaSso2ClientApplication {
(1) 依次启动 `SSO-Server` 与 `SSO-Client`,然后从浏览器访问:[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
+
+

(2) 首次打开,提示当前未登录,我们点击 **`登录`** 按钮,页面会被重定向到登录中心
@@ -282,10 +292,121 @@ public class SaSso2ClientApplication {
默认测试密码:`sa / 123456`,其余流程保持不变
-->
+
+
+### 5、无刷单点注销
+
+有了单点登录,就必然伴随着单点注销(一处注销,全端下线)
+
+如果你的所有 client 都是基于 SSO 模式二来对接的,那么单点注销其实很简单:
+
+``` java
+// 在 `sa-token.is-share=true` 的情况下,调用此代码即可单点注销:
+StpUtil.logout();
+
+// 在 `sa-token.is-share=false` 的情况下,调用此代码即可单点注销:
+StpUtil.logout(StpUtil.getLoginId());
+```
+
+你可能会比较疑惑,这不就是个普通的会话注销API吗,为什么会有单点注销的效果?
+
+因为模式二需要各个 sso-client 和 sso-server 连接同一个 redis,即使登录再多的 client,本质上对应的仍是同一个会话,因此可以做到任意一处调用注销,全端一起下线的效果。
+
+而如果你的各个 client 架构各不相同,有的是模式二对接,有的是模式三对接,则需要麻烦一点才能做到单点注销。
+
+这里的“麻烦”指两处:1、框架内部逻辑麻烦;2、开发者集成麻烦。
+
+框架内部的麻烦 sa-token-sso 已经封装完毕,无需过多关注,而开发者的麻烦步骤也不是很多:
+#### 5.1、增加 pom.xml 配置
-### 5、跨 Redis 的单点登录
+
+
+``` xml
+
+
+ com.dtflys.forest
+ forest-spring-boot-starter
+ 1.5.26
+
+```
+
+``` gradle
+// Http请求工具
+implementation 'com.dtflys.forest:forest-spring-boot-starter:1.5.26'
+```
+
+
+Forest 是一个轻量级 http 请求工具,详情参考:[Forest](https://forest.dtflyx.com/)
+
+因为我们已经在控制台手动打印 url 请求日志了,所以此处 `forest.log-enabled=false` 关闭 Forest 框架自身的日志打印,这不是必须的,你可以将其打开。
+
+
+#### 5.2、SSO-Client 端新增配置:API调用秘钥
+
+在 `application.yml` 增加:
+
+
+
+``` yaml
+sa-token:
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+
+forest:
+ # 关闭 forest 请求日志打印
+ log-enabled: false
+```
+
+``` properties
+# 接口调用秘钥
+sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+```
+
+
+注意 secretkey 秘钥需要与SSO认证中心的一致
+
+#### 5.3、SSO-Client 配置 http 请求处理器
+``` java
+// 配置SSO相关参数
+@Autowired
+private void configSso(SaSsoClientConfig ssoClient) {
+ // 配置Http请求处理器
+ ssoClient.sendHttp = url -> {
+ System.out.println("------ 发起请求:" + url);
+ String resStr = Forest.get(url).executeAsString();
+ System.out.println("------ 请求结果:" + resStr);
+ return resStr;
+ };
+}
+```
+
+#### 5.3、启动测试
+重启项目,依次登录三个 client:
+- [http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
+- [http://sa-sso-client2.com:9001/](http://sa-sso-client2.com:9001/)
+- [http://sa-sso-client3.com:9001/](http://sa-sso-client3.com:9001/)
+
+
+
+在任意一个 client 里,点击 **`[注销]`** 按钮,即可单点注销成功(打开另外两个client,刷新一下页面,登录态丢失)。
+
+
+
+
+
+PS:这里我们为了方便演示,使用的是超链接跳页面的形式,正式项目中使用 Ajax 调用接口即可做到无刷单点登录退出。
+
+例如,我们使用 [Apifox 接口测试工具](https://www.apifox.cn/) 可以做到同样的效果:
+
+
+
+测试完毕!
+
+
+### 6、跨 Redis 的单点登录
以上流程解决了跨域模式下的单点登录,但是后端仍然采用了共享Redis来同步会话,如果我们的架构设计中Client端与Server端无法共享Redis,又该怎么完成单点登录?
这就要采用模式三了,且往下看:[SSO模式三:Http请求获取会话](/sso/sso-type3)
diff --git a/sa-token-doc/sso/sso-type3.md b/sa-token-doc/sso/sso-type3.md
index c339424f..4d9d0a5b 100644
--- a/sa-token-doc/sso/sso-type3.md
+++ b/sa-token-doc/sso/sso-type3.md
@@ -10,7 +10,7 @@
1. Client 端无法直连 Redis 校验 ticket,取出账号id。
2. Client 端无法与 Server 端共用一套会话,需要自行维护子会话。
-3. 由于不是一套会话,所以无法“一次注销,全端下线”,需要额外编写代码完成单点注销。
+3. 由于不是一套会话,所以无法“一次注销,全端下线”,需要额外编写代码完成单点注销(其实此处的“额外编写代码”已在SSO模式二“无刷单点注销”部分介绍完毕)。
所以模式三的主要目标:也就是在 模式二的基础上 解决上述 三个难题
@@ -20,76 +20,24 @@
### 2、在Client 端更改 Ticket 校验方式
-#### 2.1、增加 pom.xml 配置
-
-
-
-``` xml
-
-
- com.dtflys.forest
- forest-spring-boot-starter
- 1.5.26
-
-```
-
-``` gradle
-// Http请求工具
-implementation 'com.dtflys.forest:forest-spring-boot-starter:1.5.26'
-```
-
-
-
-> Forest 是一个轻量级 http 请求工具,详情参考:[Forest](https://forest.dtflyx.com/)
-
-#### 2.2、配置 http 请求处理器
-在SSO-Client端的 `SsoClientController` 中,新增以下配置
-``` java
-// 配置SSO相关参数
-@Autowired
-private void configSso(SaSsoConfig sso) {
- // ... 其他代码
-
- // 配置 Http 请求处理器
- sso.sendHttp = url -> {
- System.out.println("------ 发起请求:" + url);
- return Forest.get(url).executeAsString();
- };
-}
-```
-
-#### 2.3、application.yml 新增配置
+在 application.yml 新增配置:
``` yaml
sa-token:
- sso:
+ sso-client:
# 打开模式三(使用Http请求校验ticket)
is-http: true
- # SSO-Server端 ticket校验地址
- check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket
-
-forest:
- # 关闭 forest 请求日志打印
- log-enabled: false
```
``` properties
# 打开模式三(使用Http请求校验ticket)
-sa-token.sso.is-http=true
-# SSO-Server端 ticket校验地址
-sa-token.sso.check-ticket-url=http://sa-sso-server.com:9000/sso/checkTicket
-
-# 关闭 forest 请求日志打印
-forest.log-enabled: false
+sa-token.sso-client.is-http=true
```
-因为我们已经在控制台手动打印 url 请求日志了,所以此处 `forest.log-enabled=false` 关闭 Forest 框架自身的日志打印,这不是必须的,你可以将其打开。
-
-#### 2.4、启动项目测试
重启项目,访问测试:
- [http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/)
- [http://sa-sso-client2.com:9001/](http://sa-sso-client2.com:9001/)
@@ -134,23 +82,7 @@ public SaResult getData(String apiType, String loginId) {
#### 3.2、在 Client 端调用此接口查询数据
-首先在 application.yml 中配置接口地址:
-
-
-``` yaml
-sa-token:
- sso:
- # sso-server 端拉取数据地址
- get-data-url: http://sa-sso-server.com:9000/sso/getData
-```
-
-``` properties
-# sso-server 端拉取数据地址
-sa-token.sso.get-data-url=http://sa-sso-server.com:9000/sso/getData
-```
-
-
-然后在 `SsoClientController` 中新增接口
+在 `SsoClientController` 中新增接口
``` java
// 查询我的账号信息
@RequestMapping("/sso/myInfo")
@@ -242,28 +174,19 @@ public Object getFansList(Long loginId) {
}
```
-**注意:使用此方案时,需要在 client 端配置 `sa-token.sso.server-url` 地址,例如:**
-``` yaml
-sa-token:
- sso:
- # sso-server 端主机地址
- server-url: http://sa-sso-server.com:9000
-```
-
#### 4.3、访问测试
访问测试:[http://sa-sso-client1.com:9001/sso/myFansList](http://sa-sso-client1.com:9001/sso/myFansList)
+### 5、单点注销
-### 5、无刷单点注销
+有关 SSO 单点注销的步骤,在上一章节的“无刷单点注销”部分已讲解完毕(模式二和模式三通用),所以此处就不再赘述了。
-有了单点登录就必然要有单点注销,网上给出的大多数解决方案是将注销请求重定向至SSO-Server中心,逐个通知Client端下线
-
-在某些场景下,页面的跳转可能造成不太好的用户体验,Sa-Token-SSO 允许你以 `REST API` 的形式构建接口,做到页面无刷新单点注销。
+此处简单介绍一下 SSO 模式三的单点注销链路过程:
1. Client 端在校验 ticket 时,将注销回调地址发送到 Server 端。
-2. Server 端将此 Client 的注销回调地址存储到 Set 集合。
+2. Server 端将此 Client 的注销回调回调信息存储到 List 集合。
3. Client 端向 Server 端发送单点注销请求。
4. Server 端遍历Set集合,逐个通知 Client 端下线。
5. Server 端注销下线。
@@ -273,57 +196,7 @@ sa-token:
-这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文档增加以下配置即可:
-
-#### 5.1、SSO-Client 端新增配置
-
-在 `application.yml` 增加配置:`API调用秘钥` 和 `单点注销接口URL`。
-
-
-
-``` yaml
-sa-token:
- sso:
- # 单点注销地址
- slo-url: http://sa-sso-server.com:9000/sso/signout
- sign:
- # API 接口调用秘钥
- secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
-```
-
-``` properties
-# 单点注销地址
-sa-token.sso.slo-url=http://sa-sso-server.com:9000/sso/signout
-# 接口调用秘钥
-sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
-```
-
-
-
-注意 secretkey 秘钥需要与SSO认证中心的一致
-
-
-#### 5.2、启动测试
-重启项目,访问测试:[http://sa-sso-client1.com:9001/](http://sa-sso-client1.com:9001/),
-我们主要的测试点在于 `单点注销`,正常登录即可。
-
-
-
-点击 **`[注销]`** 按钮,即可单点注销成功。
-
-
-
-
-
-PS:这里我们为了方便演示,使用的是超链接跳页面的形式,正式项目中使用 Ajax 调用接口即可做到无刷单点登录退出。
-
-例如,我们使用 [Apifox 接口测试工具](https://www.apifox.cn/) 可以做到同样的效果:
-
-
-
-测试完毕!
-
-
+这些逻辑 Sa-Token 内部已经封装完毕,你只需按照文档步骤集成即可。
### 6、后记
diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java
index d5b65596..5401d2f8 100644
--- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java
+++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java
@@ -148,14 +148,10 @@ public class SaSsoClientProcessor {
// 获取对象
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
- // ---------- SSO-Client端:单点注销 [模式二]
+ // 无论登录时选择的是模式二还是模式三
+ // 在注销时都应该按照模式三的方法,通过 http 请求调用 sso-server 的单点注销接口来做到全端下线
if(cfg.getIsSlo() && ! cfg.getIsHttp()) {
- return ssoLogoutType2();
- }
-
- // ---------- SSO-Client端:单点注销 [模式三]
- if(cfg.getIsSlo() && cfg.getIsHttp()) {
- return ssoLogoutType3();
+ return ssoLogoutByMode3();
}
// 默认返回
@@ -166,7 +162,7 @@ public class SaSsoClientProcessor {
* SSO-Client端:单点注销 [模式二]
* @return 处理结果
*/
- public Object ssoLogoutType2() {
+ public Object ssoLogoutByMode2() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
@@ -185,7 +181,7 @@ public class SaSsoClientProcessor {
* SSO-Client端:单点注销 [模式三]
* @return 处理结果
*/
- public Object ssoLogoutType3() {
+ public Object ssoLogoutByMode3() {
// 获取对象
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoServerProcessor.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoServerProcessor.java
index 2f12fa92..22fea638 100644
--- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoServerProcessor.java
+++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoServerProcessor.java
@@ -223,7 +223,7 @@ public class SaSsoServerProcessor {
// step.1 校验签名
if(ssoServerTemplate.getServerConfig().getIsCheckSign()) {
- ssoServerTemplate.getSignTemplate(client).checkRequest(req, paramName.loginId);
+ ssoServerTemplate.getSignTemplate(client).checkRequest(req, paramName.client, paramName.loginId);
} else {
SaSsoManager.printNoCheckSignWarningByRuntime();
}