From 4e8b44352ff056829796f05018787e2cfb14d62b Mon Sep 17 00:00:00 2001
From: Github_lizhw <171332584@qq.com>
Date: Thu, 9 Jan 2025 23:55:27 +0800
Subject: [PATCH] =?UTF-8?q?gateway=E6=94=AF=E6=8C=81sso=E7=99=BB=E5=BD=95?=
=?UTF-8?q?=E6=A0=A1=E9=AA=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ruoyi-site/ruoyi-gateway/pom.xml | 26 ++++
.../dromara/gateway/filter/AuthFilter.java | 3 +-
.../dromara/gateway/sso/SsoController.java | 122 ++++++++++++++++++
.../dromara/gateway/sso/UserController.java | 18 +++
.../src/main/resources/application.yml | 24 ++++
5 files changed, 192 insertions(+), 1 deletion(-)
create mode 100644 ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/SsoController.java
create mode 100644 ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/UserController.java
diff --git a/ruoyi-site/ruoyi-gateway/pom.xml b/ruoyi-site/ruoyi-gateway/pom.xml
index 7b5bc93ed..8e6f4b197 100644
--- a/ruoyi-site/ruoyi-gateway/pom.xml
+++ b/ruoyi-site/ruoyi-gateway/pom.xml
@@ -66,6 +66,32 @@
ruoyi-common-satoken
+
+
+
+ cn.dev33
+ sa-token-sso
+ ${satoken.version}
+
+
+
+ cn.dev33
+ sa-token-jwt
+ ${satoken.version}
+
+
+
+
+ cn.dev33
+ sa-token-redis-jackson
+ ${satoken.version}
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
org.dromara
diff --git a/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java
index b84d8117d..06591704f 100644
--- a/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java
+++ b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java
@@ -32,7 +32,8 @@ public class AuthFilter {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**")
- .addExclude("/favicon.ico", "/actuator", "/actuator/**")
+ .addExclude("/actuator", "/actuator/**")
+ .addExclude("/favicon.ico", "/sso/getSsoAuthUrl", "/sso/isLogin", "/sso/doLoginByTicket")
// 鉴权方法:每次访问进入
.setAuth(obj -> {
// 登录校验 -- 拦截所有路由
diff --git a/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/SsoController.java b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/SsoController.java
new file mode 100644
index 000000000..b67e2376e
--- /dev/null
+++ b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/SsoController.java
@@ -0,0 +1,122 @@
+package org.dromara.gateway.sso;
+
+import cn.dev33.satoken.sso.SaSsoManager;
+import cn.dev33.satoken.sso.config.SaSsoClientConfig;
+import cn.dev33.satoken.sso.model.SaCheckTicketResult;
+import cn.dev33.satoken.sso.name.ParamName;
+import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaFoxUtil;
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 前后台分离架构下集成SSO所需的代码 (SSO-Client端),TODO 后续用户相关接口通过rpc调用获取
+ *
+ * @author click33
+ */
+@RestController
+public class SsoController {
+
+ // 当前是否登录
+ @RequestMapping("/sso/isLogin")
+ public Object isLogin() {
+ return SaResult.data(StpUtil.isLogin());
+ }
+
+ // 返回SSO认证中心登录地址
+ @RequestMapping("/sso/getSsoAuthUrl")
+ public SaResult getSsoAuthUrl(@RequestParam() String clientLoginUrl) {
+ String serverAuthUrl = buildServerAuthUrl(clientLoginUrl, "");
+ return SaResult.data(serverAuthUrl);
+ }
+
+
+ // ---------------------- 构建URL ----------------------
+
+ /**
+ * 构建URL:Server端 单点登录地址,支持vue页面的url构造
+ *
+ * @param clientLoginUrl Client端登录地址
+ * @param back 回调路径
+ * @return [SSO-Server端-认证地址 ]
+ */
+ public String buildServerAuthUrl(String clientLoginUrl, String back) {
+ SaSsoClientConfig ssoConfig = SaSsoManager.getClientConfig();
+ ParamName paramName = SaSsoClientProcessor.instance.ssoClientTemplate.paramName;
+
+ // 服务端认证地址,认证地址支持路由地址
+ String serverUrl = ssoConfig.splicingAuthUrl();
+
+ // 拼接客户端标识
+ String client = ssoConfig.getClient();
+ if (SaFoxUtil.isNotEmpty(client)) {
+ serverUrl = joinParam(serverUrl, paramName.client, client);
+ }
+
+
+ // 对back地址编码
+ back = (back == null ? "" : back);
+ back = SaFoxUtil.encodeUrl(back);
+
+ // 开始拼接 sso 统一认证地址,形如:serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
+
+ /*
+ * 部分 Servlet 版本 request.getRequestURL() 返回的 url 带有 query 参数,形如:http://domain.com?id=1,
+ * 如果不加判断会造成最终生成的 serverAuthUrl 带有双 back 参数 ,这个 if 判断正是为了解决此问题
+ */
+ if (!clientLoginUrl.contains(paramName.back + "=" + back)) {
+ clientLoginUrl = joinParam(clientLoginUrl, paramName.back, back);
+ }
+
+ // 返回
+ return joinParam(serverUrl, paramName.redirect, clientLoginUrl);
+ }
+
+ /**
+ * 在url上拼接上kv参数并返回,支持路由url 拼接
+ *
+ * @param url url
+ * @param key 参数名称
+ * @param value 参数值
+ * @return 拼接后的url字符串
+ */
+ public static String joinParam(String url, String key, Object value) {
+ // 如果url或者key为空, 直接返回
+ if (!StringUtils.hasText(url) || !StringUtils.hasText(key)) {
+ return url;
+ }
+ String routerUrlSuffix = "";
+ int routerUrlIdx = url.indexOf("#/");
+ if (routerUrlIdx != -1) {
+ routerUrlSuffix = url.substring(routerUrlIdx);
+ url = url.substring(0, routerUrlIdx);
+ }
+ return SaFoxUtil.joinParam(url, key + "=" + value) + routerUrlSuffix;
+ }
+
+
+ // 根据ticket进行登录
+ @RequestMapping("/sso/doLoginByTicket")
+ public SaResult doLoginByTicket(@RequestParam() String ticket) {
+ SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
+ StpUtil.login(ctr.loginId, ctr.remainSessionTimeout);
+ return SaResult.data(StpUtil.getTokenValue());
+ }
+
+
+ /*
+ * 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();
+ }
+
+}
diff --git a/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/UserController.java b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/UserController.java
new file mode 100644
index 000000000..013b7b5d9
--- /dev/null
+++ b/ruoyi-site/ruoyi-gateway/src/main/java/org/dromara/gateway/sso/UserController.java
@@ -0,0 +1,18 @@
+package org.dromara.gateway.sso;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class UserController {
+
+ @GetMapping("/user/getUserInfo")
+ public SaResult getUserInfo() {
+ //TODO 后续改成统一从指定用户服务取,用户应该通一接口
+ return SaResult.data(StpUtil.getTokenSession().get("loginUser"));
+ }
+
+
+}
diff --git a/ruoyi-site/ruoyi-gateway/src/main/resources/application.yml b/ruoyi-site/ruoyi-gateway/src/main/resources/application.yml
index c64e50ec3..9bdcc40d1 100644
--- a/ruoyi-site/ruoyi-gateway/src/main/resources/application.yml
+++ b/ruoyi-site/ruoyi-gateway/src/main/resources/application.yml
@@ -13,6 +13,30 @@ spring:
# 环境配置
active: @profiles.active@
+
+# sa-token配置
+sa-token:
+ sign:
+ # API client和server之间调用 接口签名秘钥 (随便乱摁几个字母即可)
+ secret-key: kQwIOrYbtXmSDkwEiFngrKidMcdrgKor
+ # token名称 (同时也是cookie名称)
+ token-name: Authorization
+ # 允许动态设置 token 有效期
+ dynamic-active-timeout: true
+ # 允许从 header 读取 token
+ is-read-header: true
+ # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险
+ is-read-cookie: false
+ # SSO-相关配置
+ sso-client:
+ # SSO-Server 端主机地址
+ server-url: http://sa-sso-server.com:19000
+ auth-url: http://localhost:9000/#/sso-login
+ client: "pc"
+ #jwt密钥
+ jwt-secret-key: abcdcosctlklmnopqrstuvwxyz
+ token-prefix: Bearer
+
--- # nacos 配置
spring:
cloud: