1
0
mirror of synced 2026-05-22 22:53:16 +00:00

Compare commits

...

18 Commits

Author SHA1 Message Date
ly-chn ee16e919fe Update thymeleaf-extend.md
有人反馈在springboot3.x版本中, 在SaTokenConfigure类注入stp, 会导致循环依赖(根据文档来搭建环境, 大部分人的SaTokenConfigure类都继承了WebMvcConfigurer)
2023-11-13 17:14:39 +08:00
click33 670cd4ae98 Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-10-31 07:47:21 +08:00
click33 4f84818100 同步赞助名单和项目友联 2023-10-31 07:47:06 +08:00
刘潇 9398f07cb5 !287 redisx 框架升为 1.6.0
Merge pull request !287 from 西东/dev
2023-10-30 22:25:56 +00:00
noear 8826565f6a redisx 框架升为 1.6.0 2023-10-18 18:18:15 +08:00
click33 e076c71648 v1.37.0 update 2023-10-18 13:22:36 +08:00
click33 f5307a2eb0 提供SpringBoot3.x路由匹配出错的解决方案 2023-10-18 02:26:35 +08:00
click33 da22832ccf 优化包结构 2023-10-18 02:26:12 +08:00
click33 6977d3d136 优化 SaTokenDao 组件更换时的逻辑 2023-10-17 12:14:42 +08:00
click33 0f7e1e977c Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev 2023-10-17 11:42:19 +08:00
click33 e918f613b8 未登录时调用鉴权 API 抛出未登录异常而不再是无权限异常。 2023-10-17 11:42:06 +08:00
刘潇 106a710dd8 !286 SaTokenDao 新增默认方法 onChange
Merge pull request !286 from moon69/dev
2023-10-17 03:40:37 +00:00
刘潇 4607f51d1a !284 解决jfinal5开启兼容json请求解析功能后报类转换异常问题
Merge pull request !284 from yangghosts/N/A
2023-10-17 03:25:27 +00:00
click33 954efeb732 修复路由拦截鉴权可被绕过的问题 fix #515 2023-10-16 16:02:19 +08:00
moon69 8db78e0a5d SaTokenDao 新增默认方法 onChange,当 SaManager.saTokenDao 变更时,调用该方法 2023-10-14 12:36:00 +08:00
yangghosts e5fb308628 解决jfinal5开启兼容json请求解析功能后报类转换异常问题
解决jfinal5开启兼容json请求解析功能后报类转换异常问题。
       //JFinal新版本已经支持直接解析contentType=application/json请求的rawdata数据了
       constants.setResolveJsonRequest(true);

java.lang.ClassCastException: io.undertow.servlet.spec.HttpServletRequestImpl cannot be cast to com.jfinal.core.paragetter.JsonRequest
	at com.jfinal.core.paragetter.ModelGetter.get(ModelGetter.java:41)
	at com.jfinal.core.paragetter.ParaProcessor.get(ParaProcessor.java:51)
	at com.jfinal.aop.Invocation.<init>(Invocation.java:86)
	at cn.dev33.satoken.jfinal.SaTokenActionHandler.handle(SaTokenActionHandler.java:82)
	at com.jfinal.ext.handler.ContextPathHandler.handle(ContextPathHandler.java:48)
	at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:90)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

Signed-off-by: yangghosts <yangghosts@163.com>
2023-10-09 14:34:32 +00:00
click33 f2416a6175 修复小图标不能正常显示的问题 2023-09-23 06:25:26 +08:00
click33 591ad6ac53 修复小图标不能正常显示 2023-09-22 14:14:08 +08:00
97 changed files with 919 additions and 211 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
<p align="center">
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.36.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.37.0</h1>
<h4 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h4>
<p align="center">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
+1 -1
View File
@@ -37,7 +37,7 @@
<!-- 一些属性 -->
<properties>
<revision>1.36.0</revision>
<revision>1.37.0</revision>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
+1 -1
View File
@@ -13,7 +13,7 @@
<url>https://github.com/dromara/sa-token</url>
<properties>
<revision>1.36.0</revision>
<revision>1.37.0</revision>
</properties>
<dependencyManagement>
@@ -102,10 +102,13 @@ public class SaManager {
SaTokenEventCenter.doRegisterComponent("SaTokenDao", saTokenDao);
}
private static void setSaTokenDaoMethod(SaTokenDao saTokenDao) {
if((SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
if (SaManager.saTokenDao != null) {
SaManager.saTokenDao.destroy();
}
SaManager.saTokenDao = saTokenDao;
if (SaManager.saTokenDao != null) {
SaManager.saTokenDao.init();
}
}
public static SaTokenDao getSaTokenDao() {
if (saTokenDao == null) {
@@ -0,0 +1,45 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.application;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 应用全局信息
*
* @author click33
* @since 1.31.0
*/
public class ApplicationInfo {
/**
* 应用前缀
*/
public static String routePrefix;
/**
* 为指定 path 裁剪掉 routePrefix 前缀
* @param path 指定 path
* @return /
*/
public static String cutPathPrefix(String path) {
if(! SaFoxUtil.isEmpty(routePrefix) && ! routePrefix.equals("/") && path.startsWith(routePrefix)){
path = path.substring(routePrefix.length());
}
return path;
}
}
@@ -199,6 +199,20 @@ public interface SaTokenDao {
* @return 查询到的数据集合
*/
List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType);
// --------------------- 生命周期 ---------------------
/**
* 当此 SaTokenDao 实例被装载时触发
*/
default void init() {
}
/**
* 当此 SaTokenDao 实例被卸载时触发
*/
default void destroy() {
}
}
@@ -40,14 +40,6 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
* 存储数据过期时间的集合(单位: 毫秒), 记录所有 key 的到期时间 (注意存储的是到期时间,不是剩余存活时间)
*/
public Map<String, Long> expireMap = new ConcurrentHashMap<>();
/**
* 构造函数
*/
public SaTokenDaoDefaultImpl() {
initRefreshThread();
}
// ------------------------ String 读写操作
@@ -260,12 +252,21 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
});
this.refreshThread.start();
}
/**
* 结束定时任务,不再定时清理过期数据
* 组件被安装时,开始刷新数据线程
*/
public void endRefreshThread() {
this.refreshFlag = false;
@Override
public void init() {
initRefreshThread();
}
/**
* 组件被卸载时,结束定时任务,不再定时清理过期数据
*/
@Override
public void destroy() {
this.refreshFlag = false;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.exception;
/**
* 一个异常:代表请求 path 无效或非法
*
* @author click33
* @since 1.37.0
*/
public class RequestPathInvalidException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 8243974276159004739L;
/** 具体无效的 path */
private final String path;
/**
* @return 具体无效的 path
*/
public String getPath() {
return path;
}
public RequestPathInvalidException(String message, String path) {
super(message);
this.path = path;
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.fun.strategy;
import cn.dev33.satoken.exception.RequestPathInvalidException;
/**
* 函数式接口:校验请求 path 的算法
*
* <p> 如果属于无效请求 path,则抛出异常 RequestPathInvalidException </p>
*
* @author click33
* @since 1.37.0
*/
@FunctionalInterface
public interface SaCheckRequestPathFunction {
/**
* 执行函数
* @param path 请求 path
* @param extArg1 扩展参数1
* @param extArg2 扩展参数2
*/
void run(String path, Object extArg1, Object extArg2);
}
@@ -0,0 +1,37 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.fun.strategy;
import cn.dev33.satoken.exception.RequestPathInvalidException;
/**
* 函数式接口:当请求 path 校验不通过时处理方案的算法
*
* @author click33
* @since 1.37.0
*/
@FunctionalInterface
public interface SaRequestPathInvalidHandleFunction {
/**
* 执行函数
* @param e 请求 path 无效的异常对象
* @param extArg1 扩展参数1
* @param extArg2 扩展参数2
*/
void run(RequestPathInvalidException e, Object extArg1, Object extArg2);
}
@@ -1175,6 +1175,11 @@ public class StpLogic {
*/
public SaSession getSessionBySessionId(String sessionId, boolean isCreate, Consumer<SaSession> appendOperation) {
// 如果提供的 sessionId 为 null,则直接返回 null
if(SaFoxUtil.isEmpty(sessionId)) {
return null;
}
// 先检查这个 SaSession 是否已经存在,如果不存在且 isCreate=true,则新建并返回
SaSession session = getSaTokenDao().getSession(sessionId);
@@ -1725,11 +1730,7 @@ public class StpLogic {
* @return /
*/
public List<String> getRoleList() {
try {
return getRoleList(getLoginId());
} catch (NotLoginException e) {
return SaFoxUtil.emptyList();
}
return getRoleList(getLoginId());
}
/**
@@ -1773,7 +1774,7 @@ public class StpLogic {
try {
checkRoleAnd(roleArray);
return true;
} catch (NotLoginException | NotRoleException e) {
} catch (NotRoleException e) {
return false;
}
}
@@ -1788,7 +1789,7 @@ public class StpLogic {
try {
checkRoleOr(roleArray);
return true;
} catch (NotLoginException | NotRoleException e) {
} catch (NotRoleException e) {
return false;
}
}
@@ -1863,11 +1864,7 @@ public class StpLogic {
* @return /
*/
public List<String> getPermissionList() {
try {
return getPermissionList(getLoginId());
} catch (NotLoginException e) {
return SaFoxUtil.emptyList();
}
return getPermissionList(getLoginId());
}
/**
@@ -1911,7 +1908,7 @@ public class StpLogic {
try {
checkPermissionAnd(permissionArray);
return true;
} catch (NotLoginException | NotPermissionException e) {
} catch (NotPermissionException e) {
return false;
}
}
@@ -1926,7 +1923,7 @@ public class StpLogic {
try {
checkPermissionOr(permissionArray);
return true;
} catch (NotLoginException | NotPermissionException e) {
} catch (NotPermissionException e) {
return false;
}
}
@@ -18,6 +18,7 @@ package cn.dev33.satoken.strategy;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.exception.RequestPathInvalidException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.fun.strategy.*;
import cn.dev33.satoken.session.SaSession;
@@ -329,6 +330,49 @@ public final class SaStrategy {
return new StpLogic(loginType);
};
/**
* 请求 path 不允许出现的字符
*/
public static String[] INVALID_CHARACTER = {
"//", "\\",
"%2e", "%2E", // .
"%2f", "%2F", // /
"%5c", "%5C", // \
"%25" // 空格
};
/**
* 校验请求 path 的算法
*/
public SaCheckRequestPathFunction checkRequestPath = (requestPath, extArg1, extArg2) -> {
// 不允许为null
if(requestPath == null) {
throw new RequestPathInvalidException("非法请求:null", null);
}
// 不允许包含非法字符
for (String item : INVALID_CHARACTER) {
if (requestPath.contains(item)) {
throw new RequestPathInvalidException("非法请求:" + requestPath, requestPath);
}
}
// 不允许出现跨目录
if(requestPath.contains("/.") || requestPath.contains("\\.")) {
throw new RequestPathInvalidException("非法请求:" + requestPath, requestPath);
}
};
/**
* 当请求 path 校验不通过时处理方案的算法,自定义示例:
* <pre>
* SaStrategy.instance.requestPathInvalidHandle = (e, extArg1, extArg2) -> {
* // 自定义处理逻辑 ...
* };
* </pre>
*/
public SaRequestPathInvalidHandleFunction requestPathInvalidHandle = null;
// ----------------------- 重写策略 set连缀风格
@@ -36,7 +36,7 @@ public class SaTokenConsts {
/**
* Sa-Token 当前版本号
*/
public static final String VERSION_NO = "v1.36.0";
public static final String VERSION_NO = "v1.37.0";
/**
* Sa-Token 开源地址 Gitee
@@ -186,6 +186,28 @@ public class SaTokenConsts {
*/
public static final int ASSEMBLY_ORDER = -100;
/**
* 请求 path 校验过滤器的注册顺序
*/
public static final int PATH_CHECK_FILTER_ORDER = -1000;
/**
* Content-Type key
*/
public static final String CONTENT_TYPE_KEY = "Content-Type";
/**
* Content-Type text/plain; charset=utf-8
*/
public static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain; charset=utf-8";
/**
* Content-Type application/json;charset=UTF-8
*/
public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json;charset=UTF-8";
// =================== 废弃 ===================
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -73,7 +73,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-bom</artifactId>
<version>1.36.0</version>
<version>1.37.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
+1 -1
View File
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenCrossCookieApplication</java.run.main.class>
</properties>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenCrossHeaderApplication</java.run.main.class>
</properties>
@@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>
@@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<dubbo.version>2.7.21</dubbo.version>
<nacos.version>1.4.2</nacos.version>
</properties>
@@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
@@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<dubbo.version>3.2.2</dubbo.version>
<nacos.version>2.2.2</nacos.version>
</properties>
+1 -1
View File
@@ -27,7 +27,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.10</lombok.version>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
+1 -1
View File
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 定义 Sa-Token 版本号 -->
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<!-- 定义 Sa-Token 版本号 -->
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
</parent>
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
+1 -1
View File
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -1,10 +1,11 @@
package com.pj.test;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.util.SaResult;
/**
* 测试专用Controller
* @author click33
@@ -27,4 +28,13 @@ public class TestController {
return SaResult.ok();
}
// 测试 浏览器访问: http://localhost:8081/test/getRequestPath
@RequestMapping("getRequestPath")
public SaResult getRequestPath() {
System.out.println("-------------- 测试请求 path 获取");
System.out.println("request.getRequestURI() " + SpringMVCUtil.getRequest().getRequestURI());
System.out.println("saRequest.getRequestPath() " + SaHolder.getRequest().getRequestPath());
return SaResult.ok();
}
}
@@ -19,7 +19,7 @@ sa-token:
# 是否输出操作日志
is-log: true
spring:
spring:
data:
# redis配置
redis:
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<solon.version>2.2.3</solon.version>
</properties>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
+2 -1
View File
@@ -11,13 +11,14 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.14</version>
<!--<version>2.3.0.RELEASE</version>-->
<!-- <version>1.5.9.RELEASE</version> -->
<relativePath/>
</parent>
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
<java.run.main.class>com.pj.SaTokenApplication</java.run.main.class>
</properties>
@@ -23,5 +23,5 @@ public class NotFoundHandle implements ErrorController {
response.setStatus(200);
return SaResult.get(404, "not found", null);
}
}
@@ -1,5 +1,7 @@
package com.pj.test;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
@@ -41,4 +43,13 @@ public class TestController {
return SaResult.ok();
}
// 测试 浏览器访问: http://localhost:8081/test/getRequestPath
@RequestMapping("getRequestPath")
public SaResult getRequestPath() {
System.out.println("------------ 测试访问路径获取 ");
System.out.println("SpringMVCUtil.getRequest().getRequestURI() " + SpringMVCUtil.getRequest().getRequestURI());
System.out.println("SaHolder.getRequest().getRequestPath() " + SaHolder.getRequest().getRequestPath());
return SaResult.ok();
}
}
@@ -19,7 +19,7 @@ sa-token:
# 是否输出操作日志
is-log: true
spring:
spring:
# redis配置
redis:
# Redis数据库索引(默认为0
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -1,10 +1,9 @@
package com.pj;
import cn.dev33.satoken.SaManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import cn.dev33.satoken.SaManager;
/**
* Sa-Token整合webflux 示例 (springboot3)
*
@@ -19,7 +19,7 @@ sa-token:
# 是否输出操作日志
is-log: true
spring:
spring:
# redis配置
redis:
# Redis数据库索引(默认为0
+1 -1
View File
@@ -16,7 +16,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -19,7 +19,7 @@ sa-token:
# 是否输出操作日志
is-log: true
spring:
spring:
# redis配置
redis:
# Redis数据库索引(默认为0
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
@@ -17,7 +17,7 @@
<!-- 定义 Sa-Token 版本号 -->
<properties>
<sa-token.version>1.36.0</sa-token.version>
<sa-token.version>1.37.0</sa-token.version>
</properties>
<dependencies>
+3 -3
View File
@@ -12,7 +12,7 @@
<description>Sa-Token Dependencies</description>
<properties>
<revision>1.36.0</revision>
<revision>1.37.0</revision>
<!-- 统一定义依赖版本号 -->
<springboot.version>2.5.15</springboot.version>
@@ -24,8 +24,8 @@
<jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<solon.version>2.5.3</solon.version>
<noear-redisx.version>1.4.8</noear-redisx.version>
<noear-snack3.version>3.2.79</noear-snack3.version>
<noear-redisx.version>1.6.0</noear-redisx.version>
<noear-snack3.version>3.2.80</noear-snack3.version>
<jfinal.version>4.9.17</jfinal.version>
<jboot.version>3.14.4</jboot.version>
<commons-pool2.version>2.5.0</commons-pool2.version>
+1 -1
View File
@@ -1,7 +1,7 @@
<p align="center">
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.36.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.37.0</h1>
<h5 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h5>
<p align="center" class="badge-box">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
+4 -3
View File
@@ -18,7 +18,7 @@
<div class="logo-box">
<img src="logo.png" title="logo" />
<h1 class="logo-text">Sa-Token</h1>
<sub>v1.36.0</sub>
<sub>v1.37.0</sub>
</div>
</a>
</div>
@@ -28,6 +28,7 @@
</div>
<select class="select-version p-none" onchange="location.href=this.value">
<option value="doc.html">最新版</option>
<option value="v/v1.36.0/doc.html">v1.36.0</option>
<option value="v/v1.35.0/doc.html">v1.35.0</option>
<option value="v/v1.34.0/doc.html">v1.34.0</option>
<option value="v/v1.33.0/doc.html">v1.33.0</option>
@@ -103,7 +104,7 @@
<!-- <a class="p-none wzi" href="#/more/blog">博客</a> -->
<a class="p-none wzi" href="#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="#/sso/sso-pro">?? SSO商业版</a>
<a class="p-none wzi" href="#/sso/sso-pro">🔥 SSO商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
<span>相关资源 </span>
@@ -166,7 +167,7 @@
<script src="./static/docsify-plugin.js?v=6"></script>
<script src="./static/is-star-plugin.js?v=6"></script>
<script>
var saTokenTopVersion = '1.36.0'; // Sa-Token最新版本
var saTokenTopVersion = '1.37.0'; // Sa-Token最新版本
var name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v' + saTokenTopVersion + '</sub>';
window.$docsify = {
+18 -9
View File
@@ -67,7 +67,7 @@
<!-- <a class="p-none wzi" href="doc.html#/more/blog">博客</a> -->
<a class="p-none wzi" href="doc.html#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="doc.html#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="doc.html#/sso/sso-pro">?? SSO商业版</a>
<a class="p-none wzi" href="doc.html#/sso/sso-pro">🔥 SSO商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
<span>相关资源 </span>
@@ -109,7 +109,7 @@
<div class="main-box">
<div class="content-box">
<!-- <div class="fenge"></div> -->
<h1>Sa-Token<small>v1.36.0</small></h1>
<h1>Sa-Token<small>v1.37.0</small></h1>
<div class="sub-title">一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!</div>
<div class="btn-box">
<a class="abtn" href="https://github.com/dromara/sa-token" target="_blank">GitHub</a>
@@ -147,7 +147,7 @@
<p>多端登录、单端登录、同端互斥登录、七天免登录…… 多种登录策略只需改个配置即可完成</p>
</div>
<div class="feature">
<h2>?? 权限认证</h2>
<h2>🔑️ 权限认证</h2>
<p>权限认证、角色认证、会话二级认证、注解鉴权、路由鉴权……多种姿势灵活鉴权</p>
</div>
<div class="feature">
@@ -155,27 +155,27 @@
<p>强制注销、踢人下线、账号封禁、身份切换、自动续签 …… 提供完善的会话管理方案</p>
</div>
<div class="feature">
<h2>?? Redis集成</h2>
<h2>🔎 Redis集成</h2>
<p>提供 Redis 集成方案、项目重启数据不丢失、多系统数据互通,可自定义数据持久化策略</p>
</div>
<div class="feature">
<h2>?? 前后端分离</h2>
<h2>🚀️ 前后端分离</h2>
<p>内置多种 Token 读取策略,适配APP、小程序、SPA单页应用等前后端分离场景</p>
</div>
<div class="feature">
<h2>?? 单点登录</h2>
<h2>🍃 单点登录</h2>
<p>同域、跨域、共享Redis、跨Redis、前后端一体、前后端分离……提供各种架构下的SSO接入方案</p>
</div>
<div class="feature">
<h2>?? OAuth2.0</h2>
<h2>🍂 OAuth2.0</h2>
<p>轻松搭建 OAuth2.0 认证中心,支持四种授权模式,支持 openid 授权机制,支持二次扩展开发</p>
</div>
<div class="feature">
<h2>?? 微服务支持</h2>
<h2>💦 微服务支持</h2>
<p>分布式 Session 会话、网关统一鉴权、RPC调用鉴权……提供开箱即用的微服务认证方案</p>
</div>
<div class="feature">
<h2>?? 开箱即用</h2>
<h2>🗳 开箱即用</h2>
<p>提供SpringMVC、WebFlux、Solon、jwt 等常见框架集成包,真正的开箱即用……</p>
</div>
</div>
@@ -640,6 +640,15 @@
msg="在 SpringBoot 中通过简单的方式将文件存储到 本地、阿里云 OSS、腾讯云 COS、七牛云 Kodo等">
</a>
<a href="https://wemq.nicholasld.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/wemq.png"
msg="开源、高性能、安全、功能强大的物联网调试和管理解决方案。">
</a>
<a href="https://gitee.com/dromara/mayfly-go" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mayfly-go.png"
msg="web 版 linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库(mysql postgres)、redis(单机 哨兵 集群)、mongo 统一管理操作平台">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dromara.png"
msg="让每一位开源爱好者,体会到开源的快乐。">
+54
View File
@@ -470,6 +470,60 @@ class MyConfiguration {
[经验来源](https://gitee.com/dromara/sa-token/issues/I7EXIU)
### QSpringBoot 3.x 路由拦截鉴权报错:No more pattern data allowed after {*...} or ** pattern element
报错原因:SpringBoot3.x 版本默认将路由匹配机制由 `ant_path_matcher` 改为了 `path_pattern_parser` 模式,
而此模式有一个规则,就是写路由匹配符的时候,不允许 `**` 之后再出现内容。例如:`/admin/**/info` 就是不允许的。
如果你的项目报了这个错,说明你写的路由匹配符出现了上述问题,有三种解决方案:
1. 等待 SpringMVC 官方增强 `path_pattern_parser` 模式能力,使之可以支持 `**` 之后再出现内容。
2. 在写路由匹配规则时,避免使 `**` 之后再出现内容。
3. 将项目的路由匹配机制改为 `ant_path_matcher`。
先改项目的:
``` yml
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
```
再改 Sa-Token 的:
``` java
/**
* 自定义 SaTokenContext 实现类,重写 matchPath 方法,切换为 ant_path_matcher 模式,使之可以支持 `**` 之后再出现内容
*/
@Primary
@Component
public class SaTokenContextByPatternsRequestCondition extends SaTokenContextForSpringInJakartaServlet {
@Override
public boolean matchPath(String pattern, String path) {
return SaPatternsRequestConditionHolder.match(pattern, path);
}
}
```
<!-- ---------------------------- 常见疑问 ----------------------------- -->
+12
View File
@@ -21,6 +21,18 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永
| 赞助人 | 赞助金额 | 留言 | 时间 |
| :-------- | :-------- | :-------- | :-------- |
| [时间很快](https://gitee.com/frsimple) | ¥ 220.0 | 感谢您的开源项目! | 2023-10-27 |
| [立秋](https://gitee.com/code_wh) | ¥ 2.5 | 感谢您的开源项目! | 2023-10-27 |
| [PotatoLoofah](https://gitee.com/PotatoLoofah) | ¥ 10.0 | 感谢您的开源项目! | 2023-10-27 |
| [ly-chn](https://gitee.com/ly-chn) | ¥ 99.0 | 一定的资金支持有助于开源项目走的更加长远 | 2023-10-17 |
| [yangs2w](https://gitee.com/yangs2w) | ¥ 10.0 | 感谢您的开源项目! | 2023-10-10 |
| [lee](https://gitee.com/cngeeklee) | ¥ 10.0 | 真正的轻量级权限安全框架,希望继续更新 | 2023-10-06 |
| [yang](https://gitee.com/hansdm) | ¥ 10.0 | 感谢您的开源项目! | 2023-09-27 |
| [明道云](https://gitee.com/lunan-yn) | ¥ 200.0 | 明道云2023年伙伴大会,[报名链接](https://www.mingdao.com/event/mpc/2023) | 2023-09-25 |
| [shenlicao](https://gitee.com/shenlicao) | ¥ 10.0 | 感谢您的开源项目! | 2023-09-15 |
| [lostyue](https://gitee.com/lostyue) | ¥ 20.0 | 感谢您的开源项目! | 2023-09-14 |
| [huni](https://gitee.com/simin_sizi) | ¥ 10.0 | 感谢您的开源项目! | 2023-09-11 |
| [T_T](https://gitee.com/wm26hua) | ¥ 20.0 | 感谢您的开源项目! | 2023-09-07 |
| [Meteor](https://gitee.com/meteoroc) | ¥ 2.5 | 感谢您的开源项目! | 2023-08-23 |
| [刘斌](https://gitee.com/xuanfather) | ¥ 20.0 | 感谢您的开源项目! | 2023-08-17 |
| [快快乐乐小码农](https://gitee.com/happy-little-farmer) | ¥ 1.0 | 感谢您的开源项目! | 2023-08-17 |
+7
View File
@@ -1,5 +1,12 @@
# 更新日志
### v1.37.0 @2023-10-18
- 修复:修复路由拦截鉴权可被绕过的问题。 **[漏洞修复]**
- 重构:未登录时调用鉴权 API 抛出未登录异常而不再是无权限异常。
- 优化:优化 SaTokenDao 组件更换时的逻辑。
- 文档:提供 SpringBoot3.x 路由匹配出错的解决方案。
### v1.36.0 @2023-9-22
- sa-token-core
- 修复:API接口签名校验参数接口NPE问题,增加必须参数的非空校验处理。
+3
View File
@@ -103,7 +103,10 @@ public class SaTokenConfigure {
首先在 SaTokenConfigure 配置类中为 Thymeleaf 配置全局对象:
(注意: 如果`SaTokenConfigure`继承了`WebMvcConfigurer`等类, 可能会造成循环依赖, 如果遇到, 请新建一个其他配置类完成此项配置)
``` java
@Configuration
public class SaTokenConfigure{
// ... 其它代码
+2 -2
View File
@@ -5,14 +5,14 @@
---
### 正式版本
v1.36.0 正式版,可上生产:
v1.37.0 正式版,可上生产:
``` xml
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.36.0</version>
<version>1.37.0</version>
</dependency>
```
@@ -101,7 +101,7 @@ public class SaTokenDaoOfRedisBase64 implements SaTokenDao {
*/
@Override
public Object getObject(String key) {
return redisBucket.getAndDeserialize(key);
return redisBucket.getAndDeserialize(key, Object.class);
}
/**
@@ -156,7 +156,7 @@ public class SaTokenDaoOfRedisBase64 implements SaTokenDao {
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<>(keys);
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}
}
@@ -16,6 +16,7 @@
package cn.dev33.satoken.servlet.model;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.ApplicationInfo;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.servlet.error.SaServletErrorCode;
@@ -124,7 +125,7 @@ public class SaRequestForServlet implements SaRequest {
*/
@Override
public String getRequestPath() {
return request.getServletPath();
return ApplicationInfo.cutPathPrefix(request.getRequestURI());
}
/**
@@ -74,9 +74,12 @@ public class SaTokenActionHandler extends ActionHandler {
// Controller controller = action.getControllerClass().newInstance();
controller = controllerFactory.getController(action.getControllerClass());
CPI._init_(controller, action, request, response, urlPara[0]);
//加入SaToken上下文处理
// if (resolveJson && controller.isJsonRequest()) {
// // 注入 JsonRequest 包装对象接管 request
// controller.setHttpServletRequest(jsonRequestFactory.apply(controller.getRawData(), controller.getRequest()));
// }
//加入SaToken上下文处理
SaControllerContext.hold(controller);
if (devMode) {
if (actionReporter.isReportAfterInvocation(request)) {
new Invocation(action, controller).invoke();
@@ -0,0 +1,56 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.reactor.filter;
import cn.dev33.satoken.exception.RequestPathInvalidException;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* 校验请求 path 是否合法
*
* @author click33
* @since 1.37.0
*/
@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER)
public class SaPathCheckFilterForReactor implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// 校验本次请求 path 是否合法
try {
SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null);
} catch (RequestPathInvalidException e) {
if(SaStrategy.instance.requestPathInvalidHandle == null) {
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(e.getMessage().getBytes())));
} else {
SaStrategy.instance.requestPathInvalidHandle.run(e, exchange, null);
}
return Mono.empty();
}
// 向下执行
return chain.filter(exchange);
}
}
@@ -153,8 +153,8 @@ public class SaReactorFilter implements SaFilter, WebFilter {
// 2. 写入输出流
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
if(exchange.getResponse().getHeaders().getFirst("Content-Type") == null) {
exchange.getResponse().getHeaders().set("Content-Type", "text/plain; charset=utf-8");
if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
}
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
@@ -17,6 +17,7 @@ package cn.dev33.satoken.reactor.model;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.ApplicationInfo;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.reactor.context.SaReactorHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
@@ -112,7 +113,7 @@ public class SaRequestForReactor implements SaRequest {
*/
@Override
public String getRequestPath() {
return request.getURI().getPath();
return ApplicationInfo.cutPathPrefix(request.getPath().toString());
}
/**
@@ -16,7 +16,7 @@
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
import cn.dev33.satoken.spring.SaPathPatternParserUtil;
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
* Sa-Token 上下文处理器 [ Spring Reactor 版本实现 ] ,基于 SaTokenContextForThreadLocal 定制
@@ -15,6 +15,7 @@
*/
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.reactor.filter.SaPathCheckFilterForReactor;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.context.SaTokenContext;
@@ -37,4 +38,14 @@ public class SaTokenContextRegister {
return new SaTokenContextForSpringReactor();
}
/**
* 请求 path 校验过滤器
*
* @return /
*/
@Bean
public SaPathCheckFilterForReactor saPathCheckFilterForReactor() {
return new SaPathCheckFilterForReactor();
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.reactor.filter;
import cn.dev33.satoken.exception.RequestPathInvalidException;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* 校验请求 path 是否合法
*
* @author click33
* @since 1.37.0
*/
@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER)
public class SaPathCheckFilterForReactor implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// 校验本次请求 path 是否合法
try {
SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null);
} catch (RequestPathInvalidException e) {
if(SaStrategy.instance.requestPathInvalidHandle == null) {
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(e.getMessage().getBytes())));
} else {
SaStrategy.instance.requestPathInvalidHandle.run(e, exchange, null);
}
return Mono.empty();
}
// 向下执行
return chain.filter(exchange);
}
}
@@ -15,19 +15,10 @@
*/
package cn.dev33.satoken.reactor.filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import cn.dev33.satoken.filter.SaFilter;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
import cn.dev33.satoken.reactor.context.SaReactorHolder;
@@ -35,8 +26,16 @@ import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.error.SaReactorSpringBootErrorCode;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Reactor 全局鉴权过滤器
* <p>
@@ -154,8 +153,8 @@ public class SaReactorFilter implements SaFilter, WebFilter {
// 2. 写入输出流
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
if(exchange.getResponse().getHeaders().getFirst("Content-Type") == null) {
exchange.getResponse().getHeaders().set("Content-Type", "text/plain; charset=utf-8");
if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
}
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
@@ -16,16 +16,16 @@
package cn.dev33.satoken.reactor.model;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.ApplicationInfo;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.reactor.context.SaReactorHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.util.SaFoxUtil;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import java.util.ArrayList;
import java.util.List;
@@ -113,7 +113,7 @@ public class SaRequestForReactor implements SaRequest {
*/
@Override
public String getRequestPath() {
return request.getURI().getPath();
return ApplicationInfo.cutPathPrefix(request.getPath().toString());
}
/**
@@ -16,7 +16,7 @@
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
import cn.dev33.satoken.spring.SaPathPatternParserUtil;
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
* Sa-Token 上下文处理器 [ Spring Reactor 版本实现 ] ,基于 SaTokenContextForThreadLocal 定制
@@ -15,9 +15,9 @@
*/
package cn.dev33.satoken.reactor.spring;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.reactor.filter.SaPathCheckFilterForReactor;
import org.springframework.context.annotation.Bean;
/**
* 注册 Sa-Token 所需要的 Bean
@@ -37,4 +37,14 @@ public class SaTokenContextRegister {
return new SaTokenContextForSpringReactor();
}
/**
* 请求 path 校验过滤器
*
* @return /
*/
@Bean
public SaPathCheckFilterForReactor saPathCheckFilterForReactor() {
return new SaPathCheckFilterForReactor();
}
}
@@ -15,19 +15,19 @@
*/
package cn.dev33.satoken.servlet.model;
import java.io.IOException;
import java.util.*;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.ApplicationInfo;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.servlet.error.SaServletErrorCode;
import cn.dev33.satoken.util.SaFoxUtil;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.servlet.error.SaServletErrorCode;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.IOException;
import java.util.*;
/**
* 对 SaRequest 包装类的实现(Servlet 版)
@@ -41,15 +41,15 @@ public class SaRequestForServlet implements SaRequest {
* 底层Request对象
*/
protected HttpServletRequest request;
/**
* 实例化
* @param request request对象
* @param request request对象
*/
public SaRequestForServlet(HttpServletRequest request) {
this.request = request;
}
/**
* 获取底层源对象
*/
@@ -125,7 +125,7 @@ public class SaRequestForServlet implements SaRequest {
*/
@Override
public String getRequestPath() {
return request.getServletPath();
return ApplicationInfo.cutPathPrefix(request.getRequestURI());
}
/**
@@ -102,7 +102,7 @@ public class SaTokenDaoOfRedisBase64 implements SaTokenDao {
*/
@Override
public Object getObject(String key) {
return redisBucket.getAndDeserialize(key);
return redisBucket.getAndDeserialize(key, Object.class);
}
/**
@@ -157,7 +157,7 @@ public class SaTokenDaoOfRedisBase64 implements SaTokenDao {
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<>(keys);
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}
}
@@ -17,6 +17,7 @@ package cn.dev33.satoken.spring;
import java.util.List;
import cn.dev33.satoken.spring.pathmatch.SaPathMatcherHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.PathMatcher;
@@ -15,6 +15,7 @@
*/
package cn.dev33.satoken.spring;
import cn.dev33.satoken.spring.context.path.ApplicationContextPathLoading;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -50,5 +51,14 @@ public class SaBeanRegister {
public SaJsonTemplate getSaJsonTemplateForJackson() {
return new SaJsonTemplateForJackson();
}
/**
* 应用上下文路径加载器
* @return /
*/
@Bean
public ApplicationContextPathLoading getApplicationContextPathLoading() {
return new ApplicationContextPathLoading();
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.spring.context.path;
import cn.dev33.satoken.application.ApplicationInfo;
import cn.dev33.satoken.util.SaFoxUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
/**
* 应用上下文路径加载器
*
* @author click33
* @since 1.37.0
*/
public class ApplicationContextPathLoading implements ApplicationRunner {
@Value("${server.servlet.context-path:}")
String contextPath;
@Value("${spring.mvc.servlet.path:}")
String servletPath;
@Override
public void run(ApplicationArguments args) throws Exception {
String routePrefix = "";
if(SaFoxUtil.isNotEmpty(contextPath)) {
if(! contextPath.startsWith("/")){
contextPath = "/" + contextPath;
}
if (contextPath.endsWith("/")) {
contextPath = contextPath.substring(0, contextPath.length() - 1);
}
routePrefix += contextPath;
}
if(SaFoxUtil.isNotEmpty(servletPath)) {
if(! servletPath.startsWith("/")){
servletPath = "/" + servletPath;
}
if (servletPath.endsWith("/")) {
servletPath = servletPath.substring(0, servletPath.length() - 1);
}
routePrefix += servletPath;
}
if(SaFoxUtil.isNotEmpty(routePrefix) && ! routePrefix.equals("/") ){
ApplicationInfo.routePrefix = routePrefix;
}
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.spring;
package cn.dev33.satoken.spring.pathmatch;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.spring;
package cn.dev33.satoken.spring.pathmatch;
import org.springframework.http.server.PathContainer;
import org.springframework.web.util.pattern.PathPattern;
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.spring;
package cn.dev33.satoken.spring.pathmatch;
import cn.dev33.satoken.exception.SaTokenException;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
@@ -0,0 +1,68 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.filter;
import cn.dev33.satoken.exception.RequestPathInvalidException;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 校验请求 path 是否合法
*
* @author click33
* @since 1.37.0
*/
@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER)
public class SaPathCheckFilterForServlet implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 校验本次请求 path 是否合法
try {
HttpServletRequest req = (HttpServletRequest) request;
SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response);
} catch (RequestPathInvalidException e) {
if(SaStrategy.instance.requestPathInvalidHandle == null) {
response.setContentType("text/plain; charset=utf-8");
response.getWriter().print(e.getMessage());
response.getWriter().flush();
} else {
SaStrategy.instance.requestPathInvalidHandle.run(e, request, response);
}
return;
}
// 向下执行
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
@@ -15,26 +15,19 @@
*/
package cn.dev33.satoken.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.core.annotation.Order;
import cn.dev33.satoken.error.SaSpringBootErrorCode;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Servlet 全局鉴权过滤器
@@ -147,7 +140,7 @@ public class SaServletFilter implements SaFilter, Filter {
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
if(response.getContentType() == null) {
response.setContentType("text/plain; charset=utf-8");
response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
}
response.getWriter().print(result);
return;
@@ -22,6 +22,7 @@ import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
/**
* Sa-Token 上下文处理器 [ SpringMVC版本实现 ]。在 SpringMVC、SpringBoot 中使用 Sa-Token 时,必须注入此实现类,否则会出现上下文无效异常
@@ -15,9 +15,9 @@
*/
package cn.dev33.satoken.spring;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.filter.SaPathCheckFilterForServlet;
import org.springframework.context.annotation.Bean;
/**
* 注册 Sa-Token 框架所需要的 Bean
@@ -37,4 +37,14 @@ public class SaTokenContextRegister {
return new SaTokenContextForSpring();
}
/**
* 请求 path 校验过滤器
*
* @return /
*/
@Bean
public SaPathCheckFilterForServlet saPathCheckFilterForServlet() {
return new SaPathCheckFilterForServlet();
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.filter;
import cn.dev33.satoken.exception.RequestPathInvalidException;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.annotation.Order;
import java.io.IOException;
/**
* 校验请求 path 是否合法
*
* @author click33
* @since 1.37.0
*/
@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER)
public class SaPathCheckFilterForJakartaServlet implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 校验本次请求 path 是否合法
try {
HttpServletRequest req = (HttpServletRequest) request;
SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response);
} catch (RequestPathInvalidException e) {
if(SaStrategy.instance.requestPathInvalidHandle == null) {
response.setContentType("text/plain; charset=utf-8");
response.getWriter().print(e.getMessage());
response.getWriter().flush();
} else {
SaStrategy.instance.requestPathInvalidHandle.run(e, request, response);
}
return;
}
// 向下执行
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
@@ -15,25 +15,19 @@
*/
package cn.dev33.satoken.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.core.annotation.Order;
import cn.dev33.satoken.error.SaSpringBootErrorCode;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaTokenConsts;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.*;
import org.springframework.core.annotation.Order;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Servlet 全局鉴权过滤器
@@ -146,7 +140,7 @@ public class SaServletFilter implements SaFilter, Filter {
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
if(response.getContentType() == null) {
response.setContentType("text/plain; charset=utf-8");
response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
}
response.getWriter().print(result);
return;
@@ -22,6 +22,7 @@ import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
* Sa-Token 上下文处理器 [ SpringBoot3 Jakarta Servlet 版 ],在 SpringBoot3 中使用 Sa-Token 时,必须注入此实现类,否则会出现上下文无效异常
@@ -15,9 +15,9 @@
*/
package cn.dev33.satoken.spring;
import org.springframework.context.annotation.Bean;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.filter.SaPathCheckFilterForJakartaServlet;
import org.springframework.context.annotation.Bean;
/**
* 注册 Sa-Token 框架所需要的 Bean
@@ -37,4 +37,14 @@ public class SaTokenContextRegister {
return new SaTokenContextForSpringInJakartaServlet();
}
/**
* 请求 path 校验过滤器
*
* @return /
*/
@Bean
public SaPathCheckFilterForJakartaServlet saPathCheckFilterForJakartaServlet() {
return new SaPathCheckFilterForJakartaServlet();
}
}
@@ -15,13 +15,22 @@
*/
package cn.dev33.satoken.springboot;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.exception.*;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.json.SaJsonTemplate;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.spring.pathmatch.SaPathMatcherHolder;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import cn.dev33.satoken.util.SoMap;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@@ -31,28 +40,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.util.PathMatcher;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.exception.DisableServiceException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.exception.NotSafeException;
import cn.dev33.satoken.exception.SaJsonConvertException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.json.SaJsonTemplate;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.spring.SaPathMatcherHolder;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import cn.dev33.satoken.util.SoMap;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* Sa-Token 基础API测试
@@ -15,9 +15,9 @@
*/
package cn.dev33.satoken.springboot;
import cn.dev33.satoken.spring.SaPathMatcherHolder;
import cn.dev33.satoken.spring.SaPathPatternParserUtil;
import cn.dev33.satoken.spring.SaPatternsRequestConditionHolder;
import cn.dev33.satoken.spring.pathmatch.SaPathMatcherHolder;
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;