list2 = (List)StpUtil.getSessionByLoginId(10001).get("list");
+// for (SaSsoClientInfo info : list2) {
+// System.out.println(info);
+// }
+
}
}
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/CorsFilter.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/CorsFilter.java
deleted file mode 100644
index db7651e3..00000000
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/CorsFilter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.pj.h5;
-
-import org.noear.solon.annotation.Component;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Filter;
-import org.noear.solon.core.handle.FilterChain;
-
-
-/**
- * 跨域过滤器
- * @author click33
- */
-@Component(index = -200)
-public class CorsFilter implements Filter {
-
- static final String OPTIONS = "OPTIONS";
-
- @Override
- public void doFilter(Context ctx, FilterChain chain) throws Throwable {
- // 允许指定域访问跨域资源
- ctx.headerSet("Access-Control-Allow-Origin", "*");
- // 允许所有请求方式
- ctx.headerSet("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
- // 有效时间
- ctx.headerSet("Access-Control-Max-Age", "3600");
- // 允许的header参数
- ctx.headerSet("Access-Control-Allow-Headers", "x-requested-with,satoken");
-
- // 如果是预检请求,直接返回
- if (OPTIONS.equals(ctx.method())) {
- System.out.println("=======================浏览器发来了OPTIONS预检请求==========");
- ctx.output("");
- return;
- }
-
- // System.out.println("*********************************过滤器被使用**************************");
- chain.doFilter(ctx);
- }
-}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/H5Controller.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/H5Controller.java
index d6b2649d..d5a0ce1c 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/H5Controller.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/H5Controller.java
@@ -1,15 +1,13 @@
package com.pj.h5;
-import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.sso.template.SaSsoUtil;
+import cn.dev33.satoken.sso.util.SaSsoConsts;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Render;
/**
* 前后台分离架构下集成SSO所需的代码 (SSO-Server端)
@@ -18,40 +16,42 @@ import org.noear.solon.core.handle.Render;
*
*/
@Controller
-public class H5Controller implements Render {
+public class H5Controller {
/**
* 获取 redirectUrl
*/
@Mapping("/sso/getRedirectUrl")
- private Object getRedirectUrl(String redirect, String mode, String client) {
- // 未登录情况下,返回 code=401
- if (StpUtil.isLogin() == false) {
+ public SaResult getRedirectUrl(String client, String redirect, String mode) {
+ // 未登录情况下,返回 code=401
+ if(StpUtil.isLogin() == false) {
return SaResult.code(401);
}
- // 已登录情况下,构建 redirectUrl
- if (SaSsoConsts.MODE_SIMPLE.equals(mode)) {
- // 模式一
- SaSsoUtil.checkRedirectUrl(SaFoxUtil.decoderUrl(redirect));
+ // 已登录情况下,构建 redirectUrl
+ redirect = SaFoxUtil.decoderUrl(redirect);
+ if(SaSsoConsts.MODE_SIMPLE.equals(mode)) {
+ // 模式一
+ SaSsoUtil.checkRedirectUrl(client, redirect);
return SaResult.data(redirect);
} else {
- // 模式二或模式三
- String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), client, redirect);
+ // 模式二或模式三
+ String redirectUrl = SaSsoUtil.buildRedirectUrl(client, redirect, StpUtil.getLoginId(), StpUtil.getLoginDeviceId());
return SaResult.data(redirectUrl);
}
}
- /**
- * 控制当前类的异常
- */
- @Override
- public void render(Object data, Context ctx) throws Throwable {
- if (data instanceof Throwable) {
- Throwable e = (Throwable) data;
- e.printStackTrace();
- ctx.render(SaResult.error(e.getMessage()));
- } else {
- ctx.render(data);
- }
- }
+// /**
+// * 控制当前类的异常
+// */
+// @Override
+// public void render(Object data, Context ctx) throws Throwable {
+// if (data instanceof Throwable) {
+// Throwable e = (Throwable) data;
+// e.printStackTrace();
+// ctx.render(SaResult.error(e.getMessage()));
+// } else {
+// ctx.render(data);
+// }
+// }
+
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
new file mode 100644
index 00000000..5bd7e5ed
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
@@ -0,0 +1,40 @@
+package com.pj.h5;
+
+import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import org.noear.solon.annotation.Bean;
+import org.noear.solon.annotation.Configuration;
+
+/**
+ * [Sa-Token 权限认证] 配置类 (解决跨域问题)
+ *
+ * @author click33
+ */
+@Configuration
+public class SaTokenConfigure {
+
+ /**
+ * CORS 跨域处理策略
+ */
+ @Bean
+ public SaCorsHandleFunction corsHandle() {
+ return (req, res, sto) -> {
+ res.
+ // 允许指定域访问跨域资源
+ setHeader("Access-Control-Allow-Origin", "*")
+ // 允许所有请求方式
+ .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+ // 有效时间
+ .setHeader("Access-Control-Max-Age", "3600")
+ // 允许的header参数
+ .setHeader("Access-Control-Allow-Headers", "*");
+
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+ .back();
+ };
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
index fc311ae3..a10ec817 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
@@ -21,8 +21,8 @@ public class GlobalExceptionFilter implements Filter {
chain.doFilter(ctx);
} catch (Exception e) {
e.printStackTrace();
-
ctx.render(SaResult.error(e.getMessage()));
}
}
+
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/HomeController.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/HomeController.java
new file mode 100644
index 00000000..a3bc98d8
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/HomeController.java
@@ -0,0 +1,36 @@
+package com.pj.sso;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.stp.StpUtil;
+import org.noear.solon.annotation.Controller;
+import org.noear.solon.annotation.Mapping;
+
+/**
+ * SSO 平台中心模式示例,跳连接进入子系统
+ */
+@Controller
+public class HomeController {
+
+ // 平台化首页
+ @Mapping("/home")
+ public Object index() {
+ // 如果未登录,则先去登录
+ if(!StpUtil.isLogin()) {
+ return SaHolder.getResponse().redirect("/sso/auth");
+ }
+
+ // 拼接各个子系统的地址,格式形如:/sso/auth?client=xxx&redirect=${子系统首页}/sso/login?back=${子系统首页}
+ String link1 = "/sso/auth?client=sso-client3&redirect=http://sa-sso-client1.com:9003/sso/login?back=http://sa-sso-client1.com:9003/";
+ String link2 = "/sso/auth?client=sso-client3&redirect=http://sa-sso-client2.com:9003/sso/login?back=http://sa-sso-client2.com:9003/";
+ String link3 = "/sso/auth?client=sso-client3&redirect=http://sa-sso-client3.com:9003/sso/login?back=http://sa-sso-client3.com:9003/";
+
+ // 组织网页结构返回到前端
+ String title = "SSO 平台首页 (平台中心模式)
";
+ String client1 = " 进入Client1系统
";
+ String client2 = " 进入Client2系统
";
+ String client3 = " 进入Client3系统
";
+
+ return title + client1 + client2 + client3;
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoConfig.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoConfig.java
deleted file mode 100644
index e23de5f6..00000000
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoConfig.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.pj.sso;
-
-import cn.dev33.satoken.dao.SaTokenDao;
-import cn.dev33.satoken.dao.SaTokenDaoForRedisx;
-import cn.dev33.satoken.sso.config.SaSsoServerConfig;
-import cn.dev33.satoken.stp.StpUtil;
-import cn.dev33.satoken.util.SaResult;
-import com.dtflys.forest.Forest;
-import org.noear.solon.annotation.Bean;
-import org.noear.solon.annotation.Configuration;
-import org.noear.solon.annotation.Inject;
-import org.noear.solon.core.handle.ModelAndView;
-
-/**
- * @author noear 2023/1/3 created
- */
-@Configuration
-public class SsoConfig {
-
- /**
- * 构建建 SaToken redis dao(如果不需要 redis;可以注释掉)
- * */
- @Bean
- public SaTokenDao saTokenDaoInit(@Inject("${sa-token.dao.redis}") SaTokenDaoForRedisx saTokenDao) {
- return saTokenDao;
- }
-
- // 配置SSO相关参数
- @Bean
- public void configSso(SaSsoServerConfig ssoServer) { //SaSsoConfig 已自动构建
-
- // 配置:未登录时返回的View
- ssoServer.notLoginView = () -> {
- return new ModelAndView("sa-login.html");
- };
-
- // 配置:登录处理函数
- ssoServer.doLoginHandle = (name, pwd) -> {
- // 此处仅做模拟登录,真实环境应该查询数据进行登录
- if("sa".equals(name) && "123456".equals(pwd)) {
- StpUtil.login(10001);
- return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue());
- }
- return SaResult.error("登录失败!");
- };
-
- // 配置 Http 请求处理器
- ssoServer.sendHttp = url -> {
- try {
- System.out.println("------ 发起请求:" + url);
- String resStr = Forest.get(url).executeAsString();
- System.out.println("------ 请求结果:" + resStr);
- return resStr;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- };
- }
-}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoServerController.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoServerController.java
index babbdd87..24428337 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoServerController.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/java/com/pj/sso/SsoServerController.java
@@ -1,9 +1,18 @@
package com.pj.sso;
+import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
+import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.stp.parameter.SaLoginParameter;
+import cn.dev33.satoken.util.SaFoxUtil;
+import cn.dev33.satoken.util.SaResult;
+import org.noear.solon.annotation.Bean;
+import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
+import org.noear.solon.core.handle.ModelAndView;
/**
* Sa-Token-SSO Server端 Controller
@@ -11,17 +20,52 @@ import org.noear.solon.annotation.Mapping;
*
*/
@Controller
+@Configuration
public class SsoServerController {
- /*
- * SSO-Server端:处理所有SSO相关请求
- * 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=接口调用秘钥
+ /**
+ * SSO-Server端:处理所有SSO相关请求
+ * http://{host}:{port}/sso/auth -- 单点登录授权地址
+ * http://{host}:{port}/sso/doLogin -- 账号密码登录接口,接受参数:name、pwd
+ * http://{host}:{port}/sso/signout -- 单点注销地址(isSlo=true时打开)
*/
@Mapping("/sso/*")
public Object ssoRequest() {
return SaSsoServerProcessor.instance.dister();
}
+
+ // 配置SSO相关参数
+ @Bean
+ private void configSso(SaSsoServerTemplate ssoServerTemplate) {
+
+ // 配置:未登录时返回的View
+ ssoServerTemplate.strategy.notLoginView = () -> {
+ return new ModelAndView("sa-login.html");
+ };
+
+ // 配置:登录处理函数
+ ssoServerTemplate.strategy.doLoginHandle = (name, pwd) -> {
+ // 此处仅做模拟登录,真实环境应该查询数据库进行登录
+ if("sa".equals(name) && "123456".equals(pwd)) {
+ String deviceId = SaHolder.getRequest().getParam("deviceId", SaFoxUtil.getRandomString(32));
+ StpUtil.login(10001, new SaLoginParameter().setDeviceId(deviceId));
+ return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue());
+ }
+ return SaResult.error("登录失败!");
+ };
+
+ // 添加消息处理器:userinfo (获取用户资料) (用于为 client 端开放拉取数据的接口)
+ ssoServerTemplate.messageHolder.addHandle("userinfo", (ssoTemplate, message) -> {
+ System.out.println("收到消息:" + message);
+
+ // 自定义返回结果(模拟)
+ return SaResult.ok()
+ .set("id", message.get("loginId"))
+ .set("name", "LinXiaoYu")
+ .set("sex", "女")
+ .set("age", 18);
+ });
+
+ }
+
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/resources/app.yml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/resources/app.yml
index e895bbae..80282340 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/resources/app.yml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon/src/main/resources/app.yml
@@ -3,28 +3,50 @@ server:
port: 9000
# Sa-Token 配置
-sa-token:
- # ------- SSO-模式一相关配置 (非模式一不需要配置)
- # cookie:
- # 配置 Cookie 作用域
- # domain: stp.com
-
- # ------- SSO-模式二相关配置
+sa-token:
+ # 打印操作日志
+ is-log: true
+
+ # SSO 模式一配置 (非模式一不需要配置)
+# cookie:
+# # 配置 Cookie 作用域
+# domain: stp.com
+
+ # SSO-Server 配置
sso-server:
- # Ticket有效期 (单位: 秒),默认五分钟
+ # Ticket有效期 (单位: 秒),默认五分钟
ticket-timeout: 300
- # 所有允许的授权回调地址
+ # 主页路由:在 /sso/auth 登录页不指定 redirect 参数时,默认跳转的地址
+ home-route: /home
+ # 是否启用匿名 client (开启匿名 client 后,允许客户端接入时不提交 client 参数)
+ allow-anon-client: true
+ # 所有允许的授权回调地址 (匿名 client 使用)
allow-url: "*"
- # 是否打开单点注销功能
- isSlo: true
-
- # ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
- # 是否打开模式三
- isHttp: true
- # 接口调用秘钥(用于SSO模式三的单点注销功能)
- sign:
+ # API 接口调用秘钥 (全局默认 + 匿名 client 使用)
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
- # ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
+ # 应用列表:配置接入的应用信息
+ clients:
+ # 应用 sso-client1:采用模式一对接 (同域、同Redis)
+ sso-client1:
+ client: sso-client1
+ allowUrl: "*"
+ # 应用 sso-client2:采用模式二对接 (跨域、同Redis)
+ sso-client2:
+ client: sso-client2
+ allowUrl: "*"
+ secretKey: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+ # 应用 sso-client3:采用模式三对接 (跨域、跨Redis)
+ sso-client3:
+ # 应用名称
+ client: sso-client3
+ # 允许授权地址
+ allowUrl: "*"
+ # 是否接收消息推送
+ isPush: true
+ # 消息推送地址
+ pushUrl: http://sa-sso-client1.com:9003/sso/pushC
+ # 接口调用秘钥 (如果不配置则使用全局默认秘钥)
+ secretKey: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
sa-token.dao: #名字可以随意取
redis:
@@ -32,11 +54,7 @@ sa-token.dao: #名字可以随意取
# password: 123456
db: 1
maxTotal: 200
-
-forest:
- # 关闭 forest 请求日志打印
- log-enabled: false
-
-
+
+
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/pom.xml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/pom.xml
index 08e71b81..96f0adf1 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/pom.xml
@@ -21,11 +21,6 @@
-
-
org.noear
solon-web
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/SaSso1ClientApp.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/SaSso1ClientApp.java
index 8678b265..cbab1afa 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/SaSso1ClientApp.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/SaSso1ClientApp.java
@@ -18,12 +18,12 @@ public class SaSso1ClientApp {
System.out.println("\nSa-Token SSO模式一 Client端启动成功");
System.out.println();
- System.out.println("---------------------- Solon Sa-Token SSO 模式一 Client 端启动成功 ----------------------");
+ 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("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
System.out.println();
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/sso/SsoClientController.java
index 31d4d0a4..d0d9bba5 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/sso/SsoClientController.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/java/com/pj/sso/SsoClientController.java
@@ -1,7 +1,10 @@
package com.pj.sso;
+import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sso.SaSsoManager;
+import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
@@ -21,12 +24,16 @@ public class SsoClientController implements Render {
@Produces(MimeType.TEXT_HTML_VALUE)
@Mapping("/")
public String index() {
- String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
- String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
- String str = "Sa-Token SSO-Client 应用端
" +
- "当前会话是否登录:" + StpUtil.isLogin() + "
" +
- "登录 " +
- "注销
";
+ String url = SaFoxUtil.encodeUrl( SaFoxUtil.joinParam(SaHolder.getRequest().getUrl(), Context.current().queryString()) );
+ SaSsoClientConfig cfg = SaSsoManager.getClientConfig();
+
+ String str = "Sa-Token SSO-Client 应用端 (模式一)
" +
+ "当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")
" +
+ "" +
+ "登录 - " +
+ "单浏览器注销 - " +
+ "全端注销 " +
+ "
";
return str;
}
@@ -36,7 +43,6 @@ public class SsoClientController implements Render {
if(data instanceof Exception){
data = SaResult.error(((Exception)data).getMessage());
}
-
ctx.render(data);
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/resources/app.yml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/resources/app.yml
index d2bb8247..0ce72151 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/resources/app.yml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon/src/main/resources/app.yml
@@ -3,9 +3,14 @@ server:
port: 9001
# Sa-Token 配置
-sa-token:
+sa-token:
+ # 打印操作日志
+ is-log: true
+
# SSO-相关配置
sso-client:
+ # client 标识
+ client: sso-client1
# SSO-Server端 - 主机地址
server-url: http://sso.stp.com:9000
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/pom.xml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/pom.xml
index 90273482..306b0f57 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/pom.xml
@@ -53,12 +53,14 @@
${sa-token.version}
-
+
- org.noear
- forest-solon-plugin
+ cn.dev33
+ sa-token-forest
+ ${sa-token.version}
+
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaConfig.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaConfig.java
index a77fad4d..07b1ef50 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaConfig.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaConfig.java
@@ -2,8 +2,6 @@ package com.pj;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoForRedisx;
-import cn.dev33.satoken.sso.config.SaSsoClientConfig;
-import com.dtflys.forest.Forest;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
@@ -22,15 +20,4 @@ public class SaConfig {
return saTokenDao;
}
- @Bean
- public void configSso(SaSsoClientConfig ssoClient) {
- // 配置Http请求处理器
- ssoClient.sendHttp = url -> {
- System.out.println("------ 发起请求:" + url);
- String resStr = Forest.get(url).executeAsString();
- System.out.println("------ 请求结果:" + resStr);
- return resStr;
- };
- }
-
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaSso2ClientApp.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaSso2ClientApp.java
index a0ac5dfd..501fd8a5 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaSso2ClientApp.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/SaSso2ClientApp.java
@@ -1,6 +1,5 @@
package com.pj;
-
import cn.dev33.satoken.sso.SaSsoManager;
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/CorsFilter.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/CorsFilter.java
deleted file mode 100644
index 547aebed..00000000
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/CorsFilter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.pj.h5;
-
-import org.noear.solon.annotation.Component;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Filter;
-import org.noear.solon.core.handle.FilterChain;
-
-
-/**
- * 跨域过滤器
- * @author click33
- */
-@Component(index = -200)
-public class CorsFilter implements Filter {
- static final String OPTIONS = "OPTIONS";
-
- @Override
- public void doFilter(Context ctx, FilterChain chain) throws Throwable {
- // 允许指定域访问跨域资源
- ctx.headerSet("Access-Control-Allow-Origin", "*");
- // 允许所有请求方式
- ctx.headerSet("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
- // 有效时间
- ctx.headerSet("Access-Control-Max-Age", "3600");
- // 允许的header参数
- ctx.headerSet("Access-Control-Allow-Headers", "x-requested-with,satoken");
-
- // 如果是预检请求,直接返回
- if (OPTIONS.equals(ctx.method())) {
- System.out.println("=======================浏览器发来了OPTIONS预检请求==========");
- ctx.output("");
- return;
- }
-
- // System.out.println("*********************************过滤器被使用**************************");
- chain.doFilter(ctx);
- }
-}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/H5Controller.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/H5Controller.java
index 8ef49dd1..9ca8f1db 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/H5Controller.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/H5Controller.java
@@ -1,13 +1,13 @@
package com.pj.h5;
+import cn.dev33.satoken.sso.model.SaCheckTicketResult;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
-import cn.dev33.satoken.sso.template.SaSsoUtil;
+import cn.dev33.satoken.sso.template.SaSsoClientUtil;
import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.util.SaResult;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Render;
/**
* 前后台分离架构下集成SSO所需的代码 (SSO-Client端)
@@ -16,40 +16,30 @@ import org.noear.solon.core.handle.Render;
*
*/
@Controller
-public class H5Controller implements Render {
+public class H5Controller {
- // 当前是否登录
+ // 判断当前是否登录
@Mapping("/sso/isLogin")
public Object isLogin() {
- return SaResult.data(StpUtil.isLogin());
+ return SaResult.data(StpUtil.isLogin()).set("loginId", StpUtil.getLoginIdDefaultNull());
}
-
- // 返回SSO认证中心登录地址
+
+ // 返回SSO认证中心登录地址
@Mapping("/sso/getSsoAuthUrl")
public SaResult getSsoAuthUrl(String clientLoginUrl) {
- String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
+ String serverAuthUrl = SaSsoClientUtil.buildServerAuthUrl(clientLoginUrl, "");
return SaResult.data(serverAuthUrl);
}
-
- // 根据ticket进行登录
+
+ // 根据 ticket 进行登录
@Mapping("/sso/doLoginByTicket")
public SaResult doLoginByTicket(String ticket) {
- Object loginId = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
- if(loginId != null) {
- StpUtil.login(loginId);
- return SaResult.data(StpUtil.getTokenValue());
- }
- return SaResult.error("无效ticket:" + ticket);
+ SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket);
+ StpUtil.login(ctr.loginId, new SaLoginParameter()
+ .setTimeout(ctr.remainTokenTimeout)
+ .setDeviceId(ctr.deviceId)
+ );
+ return SaResult.data(StpUtil.getTokenValue());
}
- // 全局异常拦截并转换
- @Override
- public void render(Object data, Context ctx) throws Throwable {
- if(data instanceof Exception){
- data = SaResult.error(((Exception)data).getMessage());
- }
-
- ctx.render(data);
- }
-
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
new file mode 100644
index 00000000..5bd7e5ed
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
@@ -0,0 +1,40 @@
+package com.pj.h5;
+
+import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import org.noear.solon.annotation.Bean;
+import org.noear.solon.annotation.Configuration;
+
+/**
+ * [Sa-Token 权限认证] 配置类 (解决跨域问题)
+ *
+ * @author click33
+ */
+@Configuration
+public class SaTokenConfigure {
+
+ /**
+ * CORS 跨域处理策略
+ */
+ @Bean
+ public SaCorsHandleFunction corsHandle() {
+ return (req, res, sto) -> {
+ res.
+ // 允许指定域访问跨域资源
+ setHeader("Access-Control-Allow-Origin", "*")
+ // 允许所有请求方式
+ .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+ // 有效时间
+ .setHeader("Access-Control-Max-Age", "3600")
+ // 允许的header参数
+ .setHeader("Access-Control-Allow-Headers", "*");
+
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+ .back();
+ };
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
new file mode 100644
index 00000000..a10ec817
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
@@ -0,0 +1,28 @@
+package com.pj.sso;
+
+
+import cn.dev33.satoken.util.SaResult;
+import org.noear.solon.annotation.Component;
+import org.noear.solon.core.handle.Context;
+import org.noear.solon.core.handle.Filter;
+import org.noear.solon.core.handle.FilterChain;
+
+/**
+ * 全局异常处理
+ * @author click33
+ *
+ */
+@Component
+public class GlobalExceptionFilter implements Filter {
+
+ @Override
+ public void doFilter(Context ctx, FilterChain chain) throws Throwable {
+ try {
+ chain.doFilter(ctx);
+ } catch (Exception e) {
+ e.printStackTrace();
+ ctx.render(SaResult.error(e.getMessage()));
+ }
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/SsoClientController.java
index 76cbec98..bec46241 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/SsoClientController.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/java/com/pj/sso/SsoClientController.java
@@ -1,52 +1,83 @@
package com.pj.sso;
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
+import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
+import cn.dev33.satoken.sso.template.SaSsoClientUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
-import org.noear.solon.annotation.Controller;
-import org.noear.solon.annotation.Mapping;
-import org.noear.solon.annotation.Produces;
+import org.noear.solon.annotation.*;
import org.noear.solon.boot.web.MimeType;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Render;
/**
* Sa-Token-SSO Client端 Controller
* @author click33
*/
@Controller
-public class SsoClientController implements Render {
+@Configuration
+public class SsoClientController {
// 首页
@Produces(MimeType.TEXT_HTML_VALUE)
@Mapping("/")
public String index() {
- String str = "Sa-Token SSO-Client 应用端
" +
- "当前会话是否登录:" + StpUtil.isLogin() + "
" +
- "登录 " +
- "注销
";
+ String str = "Sa-Token SSO-Client 应用端 (模式二)
" +
+ "当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")
" +
+ " " +
+ "登录 - " +
+ "单应用注销 - " +
+ "单浏览器注销 - " +
+ "全端注销 - " +
+ "账号资料" +
+ "
";
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时打开),此接口为框架回调,开发者无需关心
+ * SSO-Client端:处理所有SSO相关请求
+ * http://{host}:{port}/sso/login -- Client 端登录地址
+ * http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
+ * http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
*/
@Mapping("/sso/*")
public Object ssoRequest() {
return SaSsoClientProcessor.instance.dister();
}
- // 全局异常拦截并转换
- @Override
- public void render(Object data, Context ctx) throws Throwable {
- if(data instanceof Exception){
- data = SaResult.error(((Exception)data).getMessage());
+ // 配置SSO相关参数
+ @Bean
+ private void configSso(SaSsoClientTemplate ssoClientTemplate) {
+
+ }
+
+ // 当前应用独自注销 (不退出其它应用)
+ @Mapping("/sso/logoutByAlone")
+ public Object logoutByAlone() {
+ StpUtil.logout();
+ return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
+ }
+
+ // 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
+ @Mapping("/sso/myInfo")
+ public Object myInfo() {
+ // 如果尚未登录
+ if( ! StpUtil.isLogin()) {
+ return "尚未登录,无法获取";
}
- ctx.render(data);
+ // 获取本地 loginId
+ Object loginId = StpUtil.getLoginId();
+
+ // 推送消息
+ SaSsoMessage message = new SaSsoMessage();
+ message.setType("userinfo");
+ message.set("loginId", loginId);
+ SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
+
+ // 返回给前端
+ return result;
}
+
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/resources/app.yml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/resources/app.yml
index 33875b88..fbe940b0 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/resources/app.yml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon/src/main/resources/app.yml
@@ -2,18 +2,21 @@
server:
port: 9002
-# sa-token配置
-sa-token:
+# sa-token配置
+sa-token:
+ # 打印操作日志
+ is-log: true
+
# SSO-相关配置
sso-client:
- # SSO-Server端 主机地址
+ # 应用标识
+ client: sso-client2
+ # SSO-Server 端主机地址
server-url: http://sa-sso-server.com:9000
+ # 在 sso-server 端前后端分离时需要单独配置 auth-url 参数(上面的不要注释,auth-url 配置项和 server-url 要同时存在)
# auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
- # 是否打开单点注销接口
- is-slo: true
- sign:
- # API 接口调用秘钥
- secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+ # API 接口调用秘钥 (单点注销时会用到)
+ secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
sa-token.dao: #名字可以随意取
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/pom.xml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/pom.xml
index 810696e8..65dbccd6 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/pom.xml
@@ -21,23 +21,12 @@
-
-
-
-
-
org.noear
solon-web
${solon.version}
-
-
- org.noear
- forest-solon-plugin
-
-
cn.dev33
@@ -59,6 +48,13 @@
${sa-token.version}
+
+
+ cn.dev33
+ sa-token-forest
+ ${sa-token.version}
+
+
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/H5Controller.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/H5Controller.java
new file mode 100644
index 00000000..9ca8f1db
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/H5Controller.java
@@ -0,0 +1,45 @@
+package com.pj.h5;
+
+import cn.dev33.satoken.sso.model.SaCheckTicketResult;
+import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
+import cn.dev33.satoken.sso.template.SaSsoClientUtil;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.stp.parameter.SaLoginParameter;
+import cn.dev33.satoken.util.SaResult;
+import org.noear.solon.annotation.Controller;
+import org.noear.solon.annotation.Mapping;
+
+/**
+ * 前后台分离架构下集成SSO所需的代码 (SSO-Client端)
+ * (注:如果不需要前后端分离架构下集成SSO,可删除此包下所有代码)
+ * @author click33
+ *
+ */
+@Controller
+public class H5Controller {
+
+ // 判断当前是否登录
+ @Mapping("/sso/isLogin")
+ public Object isLogin() {
+ return SaResult.data(StpUtil.isLogin()).set("loginId", StpUtil.getLoginIdDefaultNull());
+ }
+
+ // 返回SSO认证中心登录地址
+ @Mapping("/sso/getSsoAuthUrl")
+ public SaResult getSsoAuthUrl(String clientLoginUrl) {
+ String serverAuthUrl = SaSsoClientUtil.buildServerAuthUrl(clientLoginUrl, "");
+ return SaResult.data(serverAuthUrl);
+ }
+
+ // 根据 ticket 进行登录
+ @Mapping("/sso/doLoginByTicket")
+ public SaResult doLoginByTicket(String ticket) {
+ SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket);
+ StpUtil.login(ctr.loginId, new SaLoginParameter()
+ .setTimeout(ctr.remainTokenTimeout)
+ .setDeviceId(ctr.deviceId)
+ );
+ return SaResult.data(StpUtil.getTokenValue());
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
new file mode 100644
index 00000000..5bd7e5ed
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/h5/SaTokenConfigure.java
@@ -0,0 +1,40 @@
+package com.pj.h5;
+
+import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import org.noear.solon.annotation.Bean;
+import org.noear.solon.annotation.Configuration;
+
+/**
+ * [Sa-Token 权限认证] 配置类 (解决跨域问题)
+ *
+ * @author click33
+ */
+@Configuration
+public class SaTokenConfigure {
+
+ /**
+ * CORS 跨域处理策略
+ */
+ @Bean
+ public SaCorsHandleFunction corsHandle() {
+ return (req, res, sto) -> {
+ res.
+ // 允许指定域访问跨域资源
+ setHeader("Access-Control-Allow-Origin", "*")
+ // 允许所有请求方式
+ .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+ // 有效时间
+ .setHeader("Access-Control-Max-Age", "3600")
+ // 允许的header参数
+ .setHeader("Access-Control-Allow-Headers", "*");
+
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+ .back();
+ };
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
new file mode 100644
index 00000000..a10ec817
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/GlobalExceptionFilter.java
@@ -0,0 +1,28 @@
+package com.pj.sso;
+
+
+import cn.dev33.satoken.util.SaResult;
+import org.noear.solon.annotation.Component;
+import org.noear.solon.core.handle.Context;
+import org.noear.solon.core.handle.Filter;
+import org.noear.solon.core.handle.FilterChain;
+
+/**
+ * 全局异常处理
+ * @author click33
+ *
+ */
+@Component
+public class GlobalExceptionFilter implements Filter {
+
+ @Override
+ public void doFilter(Context ctx, FilterChain chain) throws Throwable {
+ try {
+ chain.doFilter(ctx);
+ } catch (Exception e) {
+ e.printStackTrace();
+ ctx.render(SaResult.error(e.getMessage()));
+ }
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoClientController.java
index 8f3afeef..32756028 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoClientController.java
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoClientController.java
@@ -1,69 +1,82 @@
package com.pj.sso;
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.sso.message.SaSsoMessage;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
-import cn.dev33.satoken.sso.template.SaSsoUtil;
+import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
+import cn.dev33.satoken.sso.template.SaSsoClientUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
-import org.noear.solon.annotation.Controller;
-import org.noear.solon.annotation.Mapping;
-import org.noear.solon.annotation.Produces;
+import org.noear.solon.annotation.*;
import org.noear.solon.boot.web.MimeType;
-import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.handle.Render;
-
-import java.util.HashMap;
-import java.util.Map;
/**
* Sa-Token-SSO Client端 Controller
* @author click33
*/
@Controller
-public class SsoClientController implements Render {
+@Configuration
+public class SsoClientController {
// SSO-Client端:首页
@Produces(MimeType.TEXT_HTML_VALUE)
@Mapping("/")
public String index() {
- String str = "Sa-Token SSO-Client 应用端
" +
- "当前会话是否登录:" + StpUtil.isLogin() + "
" +
- "登录" +
- " 注销
";
+ String str = "Sa-Token SSO-Client 应用端 (模式三)
" +
+ "当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")
" +
+ " " +
+ "登录 - " +
+ "单应用注销 - " +
+ "单浏览器注销 - " +
+ "全端注销 - " +
+ "账号资料" +
+ "
";
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时打开),此接口为框架回调,开发者无需关心
+ * SSO-Client端:处理所有SSO相关请求
+ * http://{host}:{port}/sso/login -- Client 端登录地址
+ * http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
+ * http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
*/
@Mapping("/sso/*")
public Object ssoRequest() {
return SaSsoClientProcessor.instance.dister();
}
-
- // 查询我的账号信息
+
+ // 配置SSO相关参数
+ @Bean
+ private void configSso(SaSsoClientTemplate ssoClientTemplate) {
+
+ }
+
+ // 当前应用独自注销 (不退出其它应用)
+ @Mapping("/sso/logoutByAlone")
+ public Object logoutByAlone() {
+ StpUtil.logout();
+ return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
+ }
+
+ // 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
@Mapping("/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;
- }
-
- // 全局异常拦截并转换
- @Override
- public void render(Object data, Context ctx) throws Throwable {
- if(data instanceof Exception){
- data = SaResult.error(((Exception)data).getMessage());
+ // 如果尚未登录
+ if( ! StpUtil.isLogin()) {
+ return "尚未登录,无法获取";
}
- ctx.render(data);
+ // 获取本地 loginId
+ Object loginId = StpUtil.getLoginId();
+
+ // 推送消息
+ SaSsoMessage message = new SaSsoMessage();
+ message.setType("userinfo");
+ message.set("loginId", loginId);
+ SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
+
+ // 返回给前端
+ return result;
}
+
}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoConfig.java b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoConfig.java
deleted file mode 100644
index 1f656d62..00000000
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/java/com/pj/sso/SsoConfig.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.pj.sso;
-
-import cn.dev33.satoken.sso.config.SaSsoClientConfig;
-import com.dtflys.forest.Forest;
-import org.noear.solon.annotation.Bean;
-import org.noear.solon.annotation.Configuration;
-
-/**
- * @author noear 2023/3/13 created
- */
-@Configuration
-public class SsoConfig {
- // 配置SSO相关参数
- @Bean
- 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;
- };
- }
-}
diff --git a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/resources/app.yml b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/resources/app.yml
index 7bfeb9d3..67023924 100644
--- a/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/resources/app.yml
+++ b/sa-token-demo/sa-token-demo-sso-for-solon/sa-token-demo-sso3-client-solon/src/main/resources/app.yml
@@ -3,31 +3,29 @@ server:
port: 9003
# sa-token配置
-sa-token:
- # SSO-相关配置
- sso-client:
- # SSO-Server端 主机地址
- server-url: http://sa-sso-server.com:9000
- # 使用Http请求校验ticket
- is-http: true
- # 打开单点注销功能
- is-slo: true
- sign:
- # 接口调用秘钥
- secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+sa-token:
+ # 打印操作日志
+ is-log: true
+ # sso-client 相关配置
+ sso-client:
+ # 应用标识
+ client: sso-client3
+ # sso-server 端主机地址
+ server-url: http://sa-sso-server.com:9000
+ # 在 sso-server 端前后端分离时需要单独配置 auth-url 参数(上面的不要注释,auth-url 配置项和 server-url 要同时存在)
+ # auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
+ # 使用 Http 请求校验 ticket (模式三)
+ is-http: true
+ # API 接口调用秘钥
+ secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 配置 Sa-Token Dao(此处与SSO-Server端连接不同的Redis)
sa-token.dao: #名字可以随意取
redis:
server: "localhost:6379"
# password: 123456
- db: 2
+ db: 4
maxTotal: 200
-
-forest:
- # 关闭 forest 请求日志打印
- log-enabled: false
-
-
+
\ 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/h5/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/h5/SaTokenConfigure.java
index 663e232d..7c0dbc91 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/h5/SaTokenConfigure.java
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/h5/SaTokenConfigure.java
@@ -1,13 +1,10 @@
package com.pj.h5;
-import cn.dev33.satoken.context.SaHolder;
-import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
-import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* [Sa-Token 权限认证] 配置类 (解决跨域问题)
@@ -15,50 +12,29 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author click33
*/
@Configuration
-public class SaTokenConfigure implements WebMvcConfigurer {
+public class SaTokenConfigure {
/**
- * 注册 [Sa-Token 全局过滤器]
+ * CORS 跨域处理策略
*/
@Bean
- public SaServletFilter getSaServletFilter() {
- return new SaServletFilter()
+ public SaCorsHandleFunction corsHandle() {
+ return (req, res, sto) -> {
+ res.
+ // 允许指定域访问跨域资源
+ setHeader("Access-Control-Allow-Origin", "*")
+ // 允许所有请求方式
+ .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+ // 有效时间
+ .setHeader("Access-Control-Max-Age", "3600")
+ // 允许的header参数
+ .setHeader("Access-Control-Allow-Headers", "*");
- // 指定 [拦截路由] 与 [放行路由]
- .addInclude("/**").addExclude("/favicon.ico")
-
- // 认证函数: 每次请求执行
- .setAuth(obj -> {
- // SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
- // ...
- })
-
- // 异常处理函数:每次认证函数发生异常时执行此函数
- .setError(e -> {
- return SaResult.error(e.getMessage());
- })
-
- // 前置函数:在每次认证函数之前执行
- .setBeforeAuth(obj -> {
- SaHolder.getResponse()
-
- // ---------- 设置跨域响应头 ----------
- // 允许指定域访问跨域资源
- .setHeader("Access-Control-Allow-Origin", "*")
- // 允许所有请求方式
- .setHeader("Access-Control-Allow-Methods", "*")
- // 允许的header参数
- .setHeader("Access-Control-Allow-Headers", "*")
- // 有效时间
- .setHeader("Access-Control-Max-Age", "3600")
- ;
-
- // 如果是预检请求,则立即返回到前端
- SaRouter.match(SaHttpMethod.OPTIONS)
- .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
- .back();
- })
- ;
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+ .back();
+ };
}
}
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso1-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso1-client/src/main/resources/application.yml
index dca31e4f..ff40f804 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso1-client/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso1-client/src/main/resources/application.yml
@@ -3,7 +3,10 @@ server:
port: 9001
# Sa-Token 配置
-sa-token:
+sa-token:
+ # 打印操作日志
+ is-log: true
+
# SSO-相关配置
sso-client:
# client 标识
diff --git a/sa-token-doc/sso/anon-client.md b/sa-token-doc/sso/anon-client.md
index 13814e34..1212717d 100644
--- a/sa-token-doc/sso/anon-client.md
+++ b/sa-token-doc/sso/anon-client.md
@@ -70,7 +70,7 @@ public class CustomSaSsoServerTemplate extends SaSsoServerTemplate {
```
-### 2、在 sso-server 端开启匿名 client 接入
+### 2、在 sso-client 端不要配置 client 字段
然后在对应的应用端不要配置 client 字段,例如:
diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/config/SaSsoClientModel.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/config/SaSsoClientModel.java
index fefe9896..5cedd273 100644
--- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/config/SaSsoClientModel.java
+++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/config/SaSsoClientModel.java
@@ -42,7 +42,7 @@ public class SaSsoClientModel implements Serializable {
/**
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的 URL 将禁止下放 ticket )
*/
- public String allowUrl = "*";
+ public String allowUrl = "";
/**
* 是否接收推送消息