From dd2665ceb10d79fad00450034544460bd9232c8c Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 24 Jun 2021 18:00:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95=EF=BC=9ACA?= =?UTF-8?q?S=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/dev33/satoken/config/SaSsoConfig.java | 112 +++++++++++ .../dev33/satoken/config/SaTokenConfig.java | 26 ++- .../satoken/context/model/SaRequest.java | 6 + .../cn/dev33/satoken/sso/SaSsoConsts.java | 19 ++ .../cn/dev33/satoken/sso/SaSsoInterface.java | 180 ++++++++++++++++++ .../java/cn/dev33/satoken/sso/SaSsoUtil.java | 78 ++++++++ .../java/cn/dev33/satoken/util/SaFoxUtil.java | 105 +++++++++- .../sa-token-demo-alone-redis/pom.xml | 2 +- .../src/main/resources/application.yml | 22 +++ .../java/com/pj/SaTokenDemoApplication.java | 2 +- .../src/main/resources/application.yml | 2 +- .../sa-token-demo-sso-client/.gitignore | 12 ++ .../sa-token-demo-sso-client/pom.xml | 53 ++++++ .../java/com/pj/SaSsoClientApplication.java | 21 ++ .../java/com/pj/sso/SsoClientController.java | 49 +++++ .../src/main/java/com/pj/util/AjaxJson.java | 162 ++++++++++++++++ .../src/main/resources/application.yml | 45 +++++ .../sa-token-demo-sso-server/.gitignore | 12 ++ .../sa-token-demo-sso-server/pom.xml | 53 ++++++ .../java/com/pj/SaSsoServerApplication.java | 21 ++ .../main/java/com/pj/sso/GlobalException.java | 39 ++++ .../java/com/pj/sso/SsoServerController.java | 61 ++++++ .../src/main/java/com/pj/util/AjaxJson.java | 162 ++++++++++++++++ .../src/main/resources/application.yml | 46 +++++ .../com/pj/SaTokenWebfluxDemoApplication.java | 2 +- .../src/main/resources/application.yml | 2 +- sa-token-plugin/pom.xml | 3 +- .../reactor/model/SaRequestForReactor.java | 8 + .../servlet/model/SaRequestForServlet.java | 8 + .../solon/model/SaRequestForSolon.java | 5 + 30 files changed, 1309 insertions(+), 9 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoInterface.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java create mode 100644 sa-token-demo/sa-token-demo-sso-client/.gitignore create mode 100644 sa-token-demo/sa-token-demo-sso-client/pom.xml create mode 100644 sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/SaSsoClientApplication.java create mode 100644 sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/sso/SsoClientController.java create mode 100644 sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/util/AjaxJson.java create mode 100644 sa-token-demo/sa-token-demo-sso-client/src/main/resources/application.yml create mode 100644 sa-token-demo/sa-token-demo-sso-server/.gitignore create mode 100644 sa-token-demo/sa-token-demo-sso-server/pom.xml create mode 100644 sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java create mode 100644 sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/GlobalException.java create mode 100644 sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java create mode 100644 sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/util/AjaxJson.java create mode 100644 sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java new file mode 100644 index 00000000..219d0c4d --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java @@ -0,0 +1,112 @@ +package cn.dev33.satoken.config; + +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * Sa-Token-SSO 单点登录模块 配置Model + * @author kong + * + */ +public class SaSsoConfig { + + /** + * Ticket有效期 (单位: 秒) + */ + public long ticketTimeout = 60 * 5; + + /** + * 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) + */ + public String allowUrl = "*"; + + /** + * 调用秘钥 + */ + public String secretkey; + + /** + * SSO-Server端授权地址 + */ + public String serverUrl; + + /** + * @return SSO-Server端授权地址 + */ + public String getServerUrl() { + return serverUrl; + } + + /** + * @param serverUrl SSO-Server端授权地址 + */ + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + /** + * @return Ticket有效期 (单位: 秒) + */ + public long getTicketTimeout() { + return ticketTimeout; + } + + /** + * @param ticketTimeout Ticket有效期 (单位: 秒) + * @return 对象自身 + */ + public SaSsoConfig setTicketTimeout(long ticketTimeout) { + this.ticketTimeout = ticketTimeout; + return this; + } + + /** + * @return 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) + */ + public String getAllowUrl() { + return allowUrl; + } + + /** + * @param allowUrl 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) + * @return 对象自身 + */ + public SaSsoConfig setAllowUrl(String allowUrl) { + this.allowUrl = allowUrl; + return this; + } + + /** + * @return 调用秘钥 + */ + public String getSecretkey() { + return secretkey; + } + + /** + * @param secretkey 调用秘钥 + * @return 对象自身 + */ + public SaSsoConfig setSecretkey(String secretkey) { + this.secretkey = secretkey; + return this; + } + + @Override + public String toString() { + return "SaSsoConfig [ticketTimeout=" + ticketTimeout + ", allowUrl=" + allowUrl + ", secretkey=" + secretkey + + ", serverUrl=" + serverUrl + "]"; + } + + + + /** + * 以数组形式写入允许的授权回调地址 + * @param url 所有集合 + * @return 对象自身 + */ + public SaSsoConfig setAllow(String ...url) { + this.allowUrl = SaFoxUtil.arrayJoin(url); + return this; + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java index 22a60311..2823d9c1 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java @@ -66,6 +66,11 @@ public class SaTokenConfig { */ private String jwtSecretKey; + /** + * SSO单点登录配置对象 + */ + public SaSsoConfig sso = new SaSsoConfig(); + /** * @return token名称 (同时也是cookie名称) @@ -343,6 +348,22 @@ public class SaTokenConfig { return this; } + /** + * @return SSO单点登录配置对象 + */ + public SaSsoConfig getSso() { + return sso; + } + + + /** + * @param sso SSO单点登录配置对象 + */ + public void setSso(SaSsoConfig sso) { + this.sso = sso; + } + + /** * toString() */ @@ -354,10 +375,12 @@ public class SaTokenConfig { + tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin=" + tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain + ", tokenPrefix=" + tokenPrefix + ", isPrint=" + isPrint + ", isLog=" + isLog + ", jwtSecretKey=" - + jwtSecretKey + "]"; + + jwtSecretKey + ", sso=" + sso + "]"; } + + /** *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 setIsConcurrent() ,使用方式保持不变

* @param allowConcurrentLogin see note @@ -369,7 +392,6 @@ public class SaTokenConfig { return this; } - /** *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 setIsConcurrent() ,使用方式保持不变

* @param isV see note diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java index d0d59cf0..c4584590 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java @@ -40,6 +40,12 @@ public interface SaRequest { */ public String getRequestPath(); + /** + * 返回当前请求的url,例:http://xxx.com/?id=127 + * @return see note + */ + public String getUrl(); + /** * 返回当前请求的类型 * @return see note diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java new file mode 100644 index 00000000..aeac0479 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoConsts.java @@ -0,0 +1,19 @@ +package cn.dev33.satoken.sso; + +/** + * Sa-Token-SSO模块相关常量 + * @author kong + * + */ +public class SaSsoConsts { + + /** redirect参数名称 */ + public static final String REDIRECT_NAME = "redirect"; + + /** ticket参数名称 */ + public static final String TICKET_NAME = "ticket"; + + /** back参数名称 */ + public static final String BACK_NAME = "back"; + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoInterface.java new file mode 100644 index 00000000..1cc124bc --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoInterface.java @@ -0,0 +1,180 @@ +package cn.dev33.satoken.sso; + +import java.util.Arrays; +import java.util.List; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * Sa-Token-SSO 单点登录接口 + * @author kong + * + */ +public interface SaSsoInterface { + + /** + * 创建一个 Ticket码 + * @param loginId 账号id + * @return 票据 + */ + public default String createTicket(Object loginId) { + // 随机一个ticket + String ticket = SaFoxUtil.getRandomString(64); + + // 保存入库 + long ticketTimeout = SaManager.getConfig().getSso().getTicketTimeout(); + SaManager.getSaTokenDao().set(splicingKeyTicketToId(ticket), String.valueOf(loginId), ticketTimeout); + SaManager.getSaTokenDao().set(splicingKeyIdToTicket(loginId), String.valueOf(ticket), ticketTimeout); + + // 返回 + return ticket; + } + + /** + * 删除一个 Ticket码 + * @param ticket Ticket码 + */ + public default void deleteTicket(String ticket) { + SaManager.getSaTokenDao().delete(splicingKeyTicketToId(ticket)); + } + + /** + * 根据 账号id & 重定向地址,构建[SSO-Client端-重定向地址] + * @param loginId 账号id + * @param redirect 重定向地址 + * @return [SSO-Client端-重定向地址] + */ + public default String buildRedirectUrl(Object loginId, String redirect) { + // 校验授权地址 + checkAuthUrl(redirect); + + // 删掉旧ticket + String oldTicket = SaManager.getSaTokenDao().get(splicingKeyIdToTicket(loginId)); + if(oldTicket != null) { + deleteTicket(oldTicket); + } + + // 获取新ticket + String ticket = createTicket(loginId); + + // 构建 授权重定向地址 + redirect = encodeBackParam(redirect); + String redirectUrl = SaFoxUtil.joinParam(redirect, SaSsoConsts.TICKET_NAME + "=" + ticket); + return redirectUrl; + } + + /** + * 根据 Ticket码 获取账号id,如果Ticket码无效则返回null + * @param ticket Ticket码 + * @return 账号id + */ + public default Object getLoginId(String ticket) { + if(SaFoxUtil.isEmpty(ticket)) { + return null; + } + return SaManager.getSaTokenDao().get(splicingKeyTicketToId(ticket)); + } + + /** + * 根据 Ticket码 获取账号id,并转换为指定类型 + * @param ticket Ticket码 + * @return 账号id + */ + public default T getLoginId(String ticket, Class cs) { + return SaFoxUtil.getValueByType(getLoginId(ticket), cs); + } + + /** + * 校验url合法性 + * @param url 地址 + */ + public default void checkAuthUrl(String url) { + + // 1、是否是一个有效的url + if(SaFoxUtil.isUrl(url) == false) { + throw new SaTokenException("无效回调地址:" + url); + } + + // 2、是否在[允许地址列表]之中 + String authUrl = SaManager.getConfig().getSso().getAllowUrl(); + List authUrlList = Arrays.asList(authUrl.split(",")); + if(SaManager.getSaTokenAction().hasElement(authUrlList, url) == false) { + throw new SaTokenException("非法回调地址:" + url); + } + + // 验证通过 + return; + } + + /** + * 根据 Client端登录地址 & back地址 ,构建[SSO-Server端-认证地址] + * @param clientLoginUrl Client端登录地址 + * @param back 回调路径 + * @return [SSO-Server端-认证地址 ] + */ + public default String buildServerAuthUrl(String clientLoginUrl, String back) { + // 服务端认证地址 + String serverUrl = SaManager.getConfig().getSso().getServerUrl(); + + // 对back地址编码 + back = (back == null ? "" : back); + back = SaFoxUtil.encodeUrl(back); + + // 拼接最终地址,格式:serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com + clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, SaSsoConsts.BACK_NAME + "=" + back); + String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, SaSsoConsts.REDIRECT_NAME + "=" + clientLoginUrl); + + // 返回 + return serverAuthUrl; + } + + /** + * 对url中的back参数进行URL编码, 解决超链接重定向后参数丢失的bug + * @param url url + * @return 编码过后的url + */ + public default String encodeBackParam(String url) { + + // 获取back参数所在位置 + int index = url.indexOf("?" + SaSsoConsts.BACK_NAME + "="); + if(index == -1) { + index = url.indexOf("&" + SaSsoConsts.BACK_NAME + "="); + if(index == -1) { + return url; + } + } + + // 开始编码 + int length = SaSsoConsts.BACK_NAME.length() + 2; + String back = url.substring(index + length); + back = SaFoxUtil.encodeUrl(back); + + // 放回url中 + url = url.substring(0, index + length) + back; + return url; + } + + + // ------------------- 返回相应key ------------------- + + /** + * 拼接key:Ticket 查 账号Id + * @param ticket + * @return key + */ + public default String splicingKeyTicketToId(String ticket) { + return SaManager.getConfig().getTokenName() + ":ticket:" + ticket; + } + + /** + * 拼接key:账号Id 反查 Ticket + * @param id 账号id + * @return key + */ + public default String splicingKeyIdToTicket(Object id) { + return SaManager.getConfig().getTokenName() + ":id-ticket:" + id; + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java new file mode 100644 index 00000000..26172a9c --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java @@ -0,0 +1,78 @@ +package cn.dev33.satoken.sso; + +/** + * Sa-Token-SSO 单点登录工具类 + * @author kong + * + */ +public class SaSsoUtil { + + /** + * 底层 SaSsoServerInterface 对象 + */ + public static SaSsoInterface saSsoInterface = new SaSsoInterface() {}; + + /** + * 创建一个 Ticket票据 + * @param loginId 账号id + * @return 票据 + */ + public static String createTicket(Object loginId) { + return saSsoInterface.createTicket(loginId); + } + + /** + * 删除一个 Ticket码 + * @param ticket Ticket码 + */ + public static void deleteTicket(String ticket) { + saSsoInterface.deleteTicket(ticket); + } + + /** + * 根据 账号id & 重定向地址,构建[SSO-Client端-重定向地址] + * @param loginId 账号id + * @param redirect 重定向地址 + * @return [SSO-Client端-重定向地址] + */ + public static String buildRedirectUrl(Object loginId, String redirect) { + return saSsoInterface.buildRedirectUrl(loginId, redirect); + } + + /** + * 根据 Ticket码 获取账号id,如果Ticket码无效则返回null + * @param ticket Ticket码 + * @return 账号id + */ + public static Object getLoginId(String ticket) { + return saSsoInterface.getLoginId(ticket); + } + + /** + * 根据 Ticket码 获取账号id,并转换为指定类型 + * @param ticket Ticket码 + * @return 账号id + */ + public static T getLoginId(String ticket, Class cs) { + return saSsoInterface.getLoginId(ticket, cs); + } + + /** + * 校验url合法性 + * @param url 地址 + */ + public static void checkAuthUrl(String url) { + saSsoInterface.checkAuthUrl(url); + } + + /** + * 根据 Client端登录地址 & back地址 ,构建[SSO-Server端-认证地址] + * @param clientLoginUrl Client端登录地址 + * @param back 回调路径 + * @return [SSO-Server端-认证地址 ] + */ + public static String buildServerAuthUrl(String clientLoginUrl, String back) { + return saSsoInterface.buildServerAuthUrl(clientLoginUrl, back); + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index 42cee80e..ccd03e7d 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -1,5 +1,8 @@ package cn.dev33.satoken.util; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; @@ -9,6 +12,8 @@ import java.util.List; import java.util.Random; import java.util.regex.Pattern; +import cn.dev33.satoken.exception.SaTokenException; + /** * Sa-Token 内部工具类 * @@ -147,7 +152,6 @@ public class SaFoxUtil { return Pattern.matches(patt.replaceAll("\\*", ".*"), str); } - /** * 将指定值转化为指定类型 * @param 泛型 @@ -186,5 +190,104 @@ public class SaFoxUtil { return (T)obj3; } + /** + * 在url上拼接上kv参数并返回 + * @param url url + * @param parameStr 参数, 例如 id=1001 + * @return 拼接后的url字符串 + */ + public static String joinParam(String url, String parameStr) { + // 如果参数为空, 直接返回 + if(parameStr == null || parameStr.length() == 0) { + return url; + } + if(url == null) { + url = ""; + } + int index = url.indexOf('?'); + // ? 不存在 + if(index == -1) { + return url + '?' + parameStr; + } + // ? 是最后一位 + if(index == url.length() - 1) { + return url + parameStr; + } + // ? 是其中一位 + if(index > -1 && index < url.length() - 1) { + String separatorChar = "&"; + // 如果最后一位是 不是&, 且 parameStr 第一位不是 &, 就增送一个 & + if(url.lastIndexOf(separatorChar) != url.length() - 1 && parameStr.indexOf(separatorChar) != 0) { + return url + separatorChar + parameStr; + } else { + return url + parameStr; + } + } + // 正常情况下, 代码不可能执行到此 + return url; + } + + /** + * 将数组的所有元素使用逗号拼接在一起 + * @param arr 数组 + * @return 字符串,例: a,b,c + */ + public static String arrayJoin(String[] arr) { + if(arr == null) { + return ""; + } + String str = ""; + for (int i = 0; i < arr.length; i++) { + str += arr[i]; + if(i != arr.length - 1) { + str += ","; + } + } + return str; + } + + /** + * 验证URL的正则表达式 + */ + public static final String URL_REGEX = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]"; + + /** + * 使用正则表达式判断一个字符串是否为URL + * @param str 字符串 + * @return 拼接后的url字符串 + */ + public static boolean isUrl(String str) { + if(str == null) { + return false; + } + return str.toLowerCase().matches(URL_REGEX); + } + + /** + * URL编码 + * @param url see note + * @return see note + */ + public static String encodeUrl(String url) { + try { + return URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new SaTokenException(e); + } + } + + /** + * URL解码 + * @param url see note + * @return see note + */ + public static String decoderUrl(String url) { + try { + return URLDecoder.decode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new SaTokenException(e); + } + } + } diff --git a/sa-token-demo/sa-token-demo-alone-redis/pom.xml b/sa-token-demo/sa-token-demo-alone-redis/pom.xml index 53502013..9315a58b 100644 --- a/sa-token-demo/sa-token-demo-alone-redis/pom.xml +++ b/sa-token-demo/sa-token-demo-alone-redis/pom.xml @@ -41,7 +41,7 @@ cn.dev33 - sa-token-dao-redis + sa-token-dao-redis-jackson ${sa-token-version} diff --git a/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml index 10b3b7cf..3976cdce 100644 --- a/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml @@ -34,6 +34,28 @@ spring: # 连接池中的最小空闲连接 min-idle: 0 + # 配置业务使用的Redis连接 + redis: + # Redis数据库索引(默认为0) + database: 0 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java index 03529d66..d024c158 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java @@ -15,7 +15,7 @@ public class SaTokenDemoApplication { public static void main(String[] args) { SpringApplication.run(SaTokenDemoApplication.class, args); - System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig()); + System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig()); } } \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml index b5024ee4..f0f2da76 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml @@ -31,7 +31,7 @@ spring: # Redis服务器连接密码(默认为空) password: # 连接超时时间(毫秒) - timeout: 10000ms + timeout: 10ms lettuce: pool: # 连接池最大连接数 diff --git a/sa-token-demo/sa-token-demo-sso-client/.gitignore b/sa-token-demo/sa-token-demo-sso-client/.gitignore new file mode 100644 index 00000000..99a6e767 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/.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-client/pom.xml b/sa-token-demo/sa-token-demo-sso-client/pom.xml new file mode 100644 index 00000000..66b1461f --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + cn.dev33 + sa-token-demo-sso-client + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + 2.0.0.RELEASE + + + + + + 1.20.0 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + cn.dev33 + sa-token-spring-boot-starter + ${sa-token-version} + + + + + cn.dev33 + sa-token-dao-redis-jackson + ${sa-token-version} + + + + + org.apache.commons + commons-pool2 + + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/SaSsoClientApplication.java b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/SaSsoClientApplication.java new file mode 100644 index 00000000..0248e60e --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/SaSsoClientApplication.java @@ -0,0 +1,21 @@ +package com.pj; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import cn.dev33.satoken.SaManager; + +/** + * Sa-Token整合SpringBoot 示例 + * @author kong + * + */ +@SpringBootApplication +public class SaSsoClientApplication { + + public static void main(String[] args) throws ClassNotFoundException { + SpringApplication.run(SaSsoClientApplication.class, args); + System.out.println("\nSa-Token-SSO客户端启动成功:Sa-Token配置如下:" + SaManager.getConfig()); + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/sso/SsoClientController.java new file mode 100644 index 00000000..75269760 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/sso/SsoClientController.java @@ -0,0 +1,49 @@ +package com.pj.sso; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.sso.SaSsoUtil; +import cn.dev33.satoken.stp.StpUtil; + +/** + * Sa-Token-SSO Client端 Controller + * @author kong + */ +@RestController +public class SsoClientController { + + // Client端登录地址 + @RequestMapping("ssoLogin") + public Object login(String back, String ticket) { + // 如果当前已经登录,则无需访问SSO认证中心,可以直接返回 + System.out.println("是否已登录:" + StpUtil.isLogin()); + if(StpUtil.isLogin()) { + return new ModelAndView("redirect:" + back); + } + /* + * 接下来两种情况: + * ticket有值,说明此请求从SSO认证中心重定向而来,需要根据ticket进行登录 + * ticket无值,说明此请求是Client端访问,需要重定向至SSO认证中心 + */ + if(ticket != null) { + Object loginId = SaSsoUtil.getLoginId(ticket); + if(loginId != null ) { + // 如果ticket是有效的 (可以获取到值),需要就此登录 且清除此ticket + StpUtil.login(loginId); + SaSsoUtil.deleteTicket(ticket); + // 最后重定向回back地址 + return new ModelAndView("redirect:" + back); + } + // 此处向客户端提示ticket无效即可,不要重定向到SSO认证中心,否则容易引起无限重定向 + return "ticket无效: " + ticket; + } + + // 重定向至 SSO-Server端 认证地址 + String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(SaHolder.getRequest().getUrl(), back); + return new ModelAndView("redirect:" + serverAuthUrl); + } + +} diff --git a/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/util/AjaxJson.java b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/util/AjaxJson.java new file mode 100644 index 00000000..768d0578 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/src/main/java/com/pj/util/AjaxJson.java @@ -0,0 +1,162 @@ +package com.pj.util; + +import java.io.Serializable; +import java.util.List; + + +/** + * ajax请求返回Json格式数据的封装 + */ +public class AjaxJson implements Serializable{ + + private static final long serialVersionUID = 1L; // 序列化版本号 + + public static final int CODE_SUCCESS = 200; // 成功状态码 + public static final int CODE_ERROR = 500; // 错误状态码 + public static final int CODE_WARNING = 501; // 警告状态码 + public static final int CODE_NOT_JUR = 403; // 无权限状态码 + public static final int CODE_NOT_LOGIN = 401; // 未登录状态码 + public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码 + + public int code; // 状态码 + public String msg; // 描述信息 + public Object data; // 携带对象 + public Long dataCount; // 数据总数,用于分页 + + /** + * 返回code + * @return + */ + public int getCode() { + return this.code; + } + + /** + * 给msg赋值,连缀风格 + */ + public AjaxJson setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + /** + * 给data赋值,连缀风格 + */ + public AjaxJson setData(Object data) { + this.data = data; + return this; + } + + /** + * 将data还原为指定类型并返回 + */ + @SuppressWarnings("unchecked") + public T getData(Class cs) { + return (T) data; + } + + // ============================ 构建 ================================== + + public AjaxJson(int code, String msg, Object data, Long dataCount) { + this.code = code; + this.msg = msg; + this.data = data; + this.dataCount = dataCount; + } + + // 返回成功 + public static AjaxJson getSuccess() { + return new AjaxJson(CODE_SUCCESS, "ok", null, null); + } + public static AjaxJson getSuccess(String msg) { + return new AjaxJson(CODE_SUCCESS, msg, null, null); + } + public static AjaxJson getSuccess(String msg, Object data) { + return new AjaxJson(CODE_SUCCESS, msg, data, null); + } + public static AjaxJson getSuccessData(Object data) { + return new AjaxJson(CODE_SUCCESS, "ok", data, null); + } + public static AjaxJson getSuccessArray(Object... data) { + return new AjaxJson(CODE_SUCCESS, "ok", data, null); + } + + // 返回失败 + public static AjaxJson getError() { + return new AjaxJson(CODE_ERROR, "error", null, null); + } + public static AjaxJson getError(String msg) { + return new AjaxJson(CODE_ERROR, msg, null, null); + } + + // 返回警告 + public static AjaxJson getWarning() { + return new AjaxJson(CODE_ERROR, "warning", null, null); + } + public static AjaxJson getWarning(String msg) { + return new AjaxJson(CODE_WARNING, msg, null, null); + } + + // 返回未登录 + public static AjaxJson getNotLogin() { + return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null); + } + + // 返回没有权限的 + public static AjaxJson getNotJur(String msg) { + return new AjaxJson(CODE_NOT_JUR, msg, null, null); + } + + // 返回一个自定义状态码的 + public static AjaxJson get(int code, String msg){ + return new AjaxJson(code, msg, null, null); + } + + // 返回分页和数据的 + public static AjaxJson getPageData(Long dataCount, Object data){ + return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount); + } + + // 返回,根据受影响行数的(大于0=ok,小于0=error) + public static AjaxJson getByLine(int line){ + if(line > 0){ + return getSuccess("ok", line); + } + return getError("error").setData(line); + } + + // 返回,根据布尔值来确定最终结果的 (true=ok,false=error) + public static AjaxJson getByBoolean(boolean b){ + return b ? getSuccess("ok") : getError("error"); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @SuppressWarnings("rawtypes") + @Override + public String toString() { + String data_string = null; + if(data == null){ + + } else if(data instanceof List){ + data_string = "List(length=" + ((List)data).size() + ")"; + } else { + data_string = data.toString(); + } + return "{" + + "\"code\": " + this.getCode() + + ", \"msg\": \"" + this.getMsg() + "\"" + + ", \"data\": " + data_string + + ", \"dataCount\": " + dataCount + + "}"; + } + + + + + +} diff --git a/sa-token-demo/sa-token-demo-sso-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso-client/src/main/resources/application.yml new file mode 100644 index 00000000..77e9919e --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-client/src/main/resources/application.yml @@ -0,0 +1,45 @@ +# 端口 +server: + port: 9001 + +spring: + # sa-token配置 + sa-token: + # Token名称 + token-name: satoken + # Token有效期 + timeout: 2592000 + # Token风格 + token-style: uuid + # SSO-相关配置 + sso: + # SSO-Server端授权地址 + server-url: http://sa-sso-server.com:9000/ssoAuth + + # redis配置 + redis: + # Redis数据库索引(默认为0) + database: 0 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso-server/.gitignore b/sa-token-demo/sa-token-demo-sso-server/.gitignore new file mode 100644 index 00000000..99a6e767 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/.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-server/pom.xml b/sa-token-demo/sa-token-demo-sso-server/pom.xml new file mode 100644 index 00000000..5d9d600a --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + cn.dev33 + sa-token-demo-sso-server + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + 2.0.0.RELEASE + + + + + + 1.20.0 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + cn.dev33 + sa-token-spring-boot-starter + ${sa-token-version} + + + + + cn.dev33 + sa-token-dao-redis-jackson + ${sa-token-version} + + + + + org.apache.commons + commons-pool2 + + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java new file mode 100644 index 00000000..f2ac5be3 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/SaSsoServerApplication.java @@ -0,0 +1,21 @@ +package com.pj; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import cn.dev33.satoken.SaManager; + +/** + * Sa-Token整合SpringBoot 示例 + * @author kong + * + */ +@SpringBootApplication +public class SaSsoServerApplication { + + public static void main(String[] args) throws ClassNotFoundException { + SpringApplication.run(SaSsoServerApplication.class, args); + System.out.println("\nSa-Token-SSO 服务端启动成功:Sa-Token配置如下:" + SaManager.getConfig()); + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/GlobalException.java b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/GlobalException.java new file mode 100644 index 00000000..52ab707a --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/GlobalException.java @@ -0,0 +1,39 @@ +package com.pj.sso; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.pj.util.AjaxJson; + +/** + * 全局异常处理 + */ +@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin") +public class GlobalException { + + // 全局异常拦截(拦截项目中的所有异常) + @ResponseBody + @ExceptionHandler + public AjaxJson handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) + throws Exception { + + // 打印堆栈,以供调试 + System.out.println("全局异常---------------"); + e.printStackTrace(); + + // 不同异常返回不同状态码 + AjaxJson aj = AjaxJson.getError(e.getMessage()); + + // 返回给前端 + return aj; + + // 输出到客户端 +// response.setContentType("application/json; charset=utf-8"); // http说明,我要返回JSON对象 +// response.getWriter().print(new ObjectMapper().writeValueAsString(aj)); + } + +} diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java new file mode 100644 index 00000000..b772c485 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java @@ -0,0 +1,61 @@ +package com.pj.sso; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; + +import com.pj.util.AjaxJson; + +import cn.dev33.satoken.sso.SaSsoUtil; +import cn.dev33.satoken.stp.StpUtil; + +/** + * Sa-Token-SSO Server端 Controller + * @author kong + * + */ +@RestController +public class SsoServerController { + + // SSO-Server端:授权地址,跳转到登录页面 + @RequestMapping("ssoAuth") + public Object ssoAuth(String redirect) { + /* + * 两种情况分开处理: + * 1、如果在SSO认证中心尚未登录,则先去登登录 + * 2、如果在SSO认证中心尚已登录,则开始对redirect地址下放ticket引导授权 + */ + // 情况1:尚未登录 + if(StpUtil.isLogin() == false) { + String msg = "当前会话在SSO-Server端尚未登录,请先访问" + + " doLogin登录 " + + "进行登录之后,刷新页面开始授权"; + return msg; + } + // 情况2:已经登录,开始构建授权重定向地址,下放ticket + String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), redirect); + return new ModelAndView("redirect:" + redirectUrl); + } + + // SSO-Server端:登录接口 + @RequestMapping("doLogin") + public AjaxJson doLogin(String name, String pwd) { + if("sa".equals(name) && "123456".equals(pwd)) { + StpUtil.login(10001); + return AjaxJson.getSuccess("登录成功!"); + } + return AjaxJson.getError("登录失败!"); + } + + // SSO-Server端:根据 Ticket 获取账号id + @RequestMapping("getLoginId") + public AjaxJson getLoginId(String ticket) { + Object loginId = SaSsoUtil.getLoginId(ticket); + if(loginId != null) { + SaSsoUtil.deleteTicket(ticket); + return AjaxJson.getSuccessData(loginId); + } + return AjaxJson.getError("无效ticket: " + ticket); + } + +} diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/util/AjaxJson.java b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/util/AjaxJson.java new file mode 100644 index 00000000..768d0578 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/java/com/pj/util/AjaxJson.java @@ -0,0 +1,162 @@ +package com.pj.util; + +import java.io.Serializable; +import java.util.List; + + +/** + * ajax请求返回Json格式数据的封装 + */ +public class AjaxJson implements Serializable{ + + private static final long serialVersionUID = 1L; // 序列化版本号 + + public static final int CODE_SUCCESS = 200; // 成功状态码 + public static final int CODE_ERROR = 500; // 错误状态码 + public static final int CODE_WARNING = 501; // 警告状态码 + public static final int CODE_NOT_JUR = 403; // 无权限状态码 + public static final int CODE_NOT_LOGIN = 401; // 未登录状态码 + public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码 + + public int code; // 状态码 + public String msg; // 描述信息 + public Object data; // 携带对象 + public Long dataCount; // 数据总数,用于分页 + + /** + * 返回code + * @return + */ + public int getCode() { + return this.code; + } + + /** + * 给msg赋值,连缀风格 + */ + public AjaxJson setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + /** + * 给data赋值,连缀风格 + */ + public AjaxJson setData(Object data) { + this.data = data; + return this; + } + + /** + * 将data还原为指定类型并返回 + */ + @SuppressWarnings("unchecked") + public T getData(Class cs) { + return (T) data; + } + + // ============================ 构建 ================================== + + public AjaxJson(int code, String msg, Object data, Long dataCount) { + this.code = code; + this.msg = msg; + this.data = data; + this.dataCount = dataCount; + } + + // 返回成功 + public static AjaxJson getSuccess() { + return new AjaxJson(CODE_SUCCESS, "ok", null, null); + } + public static AjaxJson getSuccess(String msg) { + return new AjaxJson(CODE_SUCCESS, msg, null, null); + } + public static AjaxJson getSuccess(String msg, Object data) { + return new AjaxJson(CODE_SUCCESS, msg, data, null); + } + public static AjaxJson getSuccessData(Object data) { + return new AjaxJson(CODE_SUCCESS, "ok", data, null); + } + public static AjaxJson getSuccessArray(Object... data) { + return new AjaxJson(CODE_SUCCESS, "ok", data, null); + } + + // 返回失败 + public static AjaxJson getError() { + return new AjaxJson(CODE_ERROR, "error", null, null); + } + public static AjaxJson getError(String msg) { + return new AjaxJson(CODE_ERROR, msg, null, null); + } + + // 返回警告 + public static AjaxJson getWarning() { + return new AjaxJson(CODE_ERROR, "warning", null, null); + } + public static AjaxJson getWarning(String msg) { + return new AjaxJson(CODE_WARNING, msg, null, null); + } + + // 返回未登录 + public static AjaxJson getNotLogin() { + return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null); + } + + // 返回没有权限的 + public static AjaxJson getNotJur(String msg) { + return new AjaxJson(CODE_NOT_JUR, msg, null, null); + } + + // 返回一个自定义状态码的 + public static AjaxJson get(int code, String msg){ + return new AjaxJson(code, msg, null, null); + } + + // 返回分页和数据的 + public static AjaxJson getPageData(Long dataCount, Object data){ + return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount); + } + + // 返回,根据受影响行数的(大于0=ok,小于0=error) + public static AjaxJson getByLine(int line){ + if(line > 0){ + return getSuccess("ok", line); + } + return getError("error").setData(line); + } + + // 返回,根据布尔值来确定最终结果的 (true=ok,false=error) + public static AjaxJson getByBoolean(boolean b){ + return b ? getSuccess("ok") : getError("error"); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @SuppressWarnings("rawtypes") + @Override + public String toString() { + String data_string = null; + if(data == null){ + + } else if(data instanceof List){ + data_string = "List(length=" + ((List)data).size() + ")"; + } else { + data_string = data.toString(); + } + return "{" + + "\"code\": " + this.getCode() + + ", \"msg\": \"" + this.getMsg() + "\"" + + ", \"data\": " + data_string + + ", \"dataCount\": " + dataCount + + "}"; + } + + + + + +} diff --git a/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml new file mode 100644 index 00000000..6242e765 --- /dev/null +++ b/sa-token-demo/sa-token-demo-sso-server/src/main/resources/application.yml @@ -0,0 +1,46 @@ +# 端口 +server: + port: 9000 + +spring: + # Sa-Token配置 + sa-token: + # Token名称 + token-name: satoken + # Token有效期 + timeout: 2592000 + # Token风格 + token-style: uuid + # SSO单点登录-相关配置 +# sso: +# allow-url: http* + + + # redis配置 + redis: + # Redis数据库索引(默认为0) + database: 0 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 + + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java b/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java index 89081671..c3914628 100644 --- a/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java +++ b/sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/SaTokenWebfluxDemoApplication.java @@ -26,7 +26,7 @@ public class SaTokenWebfluxDemoApplication { public static void main(String[] args) { SpringApplication.run(SaTokenWebfluxDemoApplication.class, args); - System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig()); + System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig()); } } \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml index 0ee1952f..7ecd9cfa 100644 --- a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml @@ -12,7 +12,7 @@ spring: # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 activity-timeout: -1 # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - allow-concurrent-login: true + is-concurrent: true # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) is-share: true # token风格 diff --git a/sa-token-plugin/pom.xml b/sa-token-plugin/pom.xml index 3f0fd74c..1e93e670 100644 --- a/sa-token-plugin/pom.xml +++ b/sa-token-plugin/pom.xml @@ -17,11 +17,12 @@ + sa-token-alone-redis sa-token-dao-redis sa-token-dao-redis-jackson - sa-token-spring-aop sa-token-quick-login + sa-token-spring-aop sa-token-temp-jwt diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java index e98ff31c..ae54e932 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java @@ -70,6 +70,14 @@ public class SaRequestForReactor implements SaRequest { return request.getURI().getPath(); } + /** + * 返回当前请求的url,例:http://xxx.com/?id=127 + * @return see note + */ + public String getUrl() { + return request.getURI().toString(); + } + /** * 返回当前请求的类型 */ diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java index 1e1ae812..c0a28b9d 100644 --- a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java +++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java @@ -73,6 +73,14 @@ public class SaRequestForServlet implements SaRequest { return request.getServletPath(); } + /** + * 返回当前请求的url,例:http://xxx.com/?id=127 + * @return see note + */ + public String getUrl() { + return request.getRequestURL().toString(); + } + /** * 返回当前请求的类型 */ diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java index c98e7a77..4a32c964 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java @@ -40,6 +40,11 @@ public class SaRequestForSolon implements SaRequest { return ctx.pathNew(); } + @Override + public String getUrl() { + return ctx.url(); + } + @Override public String getMethod() { return ctx.method();