) so3.get("data"));
+ Assertions.assertEquals(so4.getString("tokenName"), "satoken");
+ Assertions.assertEquals(so4.getString("tokenValue"), token);
+ });
+
+ // 注销
+ requestSoMap("/acc/logout?satoken=" + token, so4 -> {
+ });
+
+ // 是否登录
+ requestSoMap("/acc/isLogin?satoken=" + token, so5 -> {
+ Assertions.assertFalse(so5.getBoolean("data"));
+ });
+
+ });
+ }
+
+ protected ValidatableResponse requestSoMap(String path, SaMapMatcher matcher) {
+ return given()
+ .when()
+ .accept(MediaType.APPLICATION_JSON)
+ .post(path)
+ .then()
+ .statusCode(200)
+ .body(matcher);
+
+ }
+
+}
diff --git a/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/MoreResourceTest.java b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/MoreResourceTest.java
new file mode 100644
index 0000000..52203c4
--- /dev/null
+++ b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/MoreResourceTest.java
@@ -0,0 +1,38 @@
+package io.quarkiverse.satoken.resteasy.integrate;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import io.quarkiverse.satoken.resteasy.AbstractRequestTest;
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+public class MoreResourceTest extends AbstractRequestTest {
+
+ // 基础API测试
+ @Test
+ public void testApi() {
+ request("/more/getInfo?name=zhang", Map.of("div", "val"), res -> {
+ Assertions.assertEquals(res.getData(), true);
+ }).statusCode(200);
+
+ }
+
+ // Http Basic 认证
+ @Test
+ public void testBasic() throws Exception {
+
+ // ---------------- 认证不通过
+ request("/more/basicAuth", res -> {
+ Assertions.assertEquals(res.getCode(), 903);
+ }).statusCode(401).header("WWW-Authenticate", "Basic Realm=Sa-Token");
+
+ // ---------------- 认证通过
+ request("/more/basicAuth", Map.of("Authorization", "Basic c2E6MTIzNDU2"), res -> {
+ Assertions.assertEquals(res.getCode(), 200);
+ }).statusCode(200);
+ }
+
+}
diff --git a/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/RouteResourceTest.java b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/RouteResourceTest.java
new file mode 100644
index 0000000..894e0d0
--- /dev/null
+++ b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/RouteResourceTest.java
@@ -0,0 +1,166 @@
+package io.quarkiverse.satoken.resteasy.integrate;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.router.SaRouterStaff;
+import io.quarkiverse.satoken.resteasy.AbstractRequestTest;
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+
+/**
+ * RouteResourceTest
+ *
+ * @author nayan
+ * @date 2022/10/9 16:26
+ */
+@QuarkusTest
+@TestProfile(RouteResourceTest.RouteTestProfile.class)
+public class RouteResourceTest extends AbstractRequestTest {
+
+ // 基础API测试
+ @Test
+ public void testApi() {
+ // 是否命中
+ SaRouterStaff staff = SaRouter.match(false);
+ Assertions.assertFalse(staff.isHit());
+
+ // 重置
+ staff.reset();
+ Assertions.assertTrue(staff.isHit());
+
+ // lambda 形式
+ SaRouterStaff staff2 = SaRouter.match(r -> false);
+ Assertions.assertFalse(staff2.isHit());
+
+ // 匹配
+ Assertions.assertTrue(SaRouter.isMatch("/user/**", "/user/add"));
+ Assertions.assertTrue(SaRouter.isMatch(new String[] { "/user/**", "/art/**", "/goods/**" }, "/art/delete"));
+ Assertions.assertTrue(SaRouter.isMatch(Arrays.asList("/user/**", "/art/**", "/goods/**"), "/art/delete"));
+ Assertions.assertTrue(SaRouter.isMatch(new String[] { "POST", "GET", "PUT" }, "GET"));
+
+ // 不匹配的
+ Assertions.assertTrue(SaRouter.notMatch(false).isHit());
+ Assertions.assertTrue(SaRouter.notMatch(r -> false).isHit());
+ }
+
+ // 各种路由测试
+ @Test
+ public void testRouter() {
+ // getInfo
+ request("/rt/getInfo?name=zhang", res -> Assertions.assertEquals(res.getCode(), 201));
+
+ // getInfo2
+ request("/rt/getInfo2", res2 -> Assertions.assertEquals(res2.getCode(), 202));
+
+ // getInfo3
+ request("/rt/getInfo3", res3 -> Assertions.assertEquals(res3.getCode(), 203));
+
+ // getInfo4
+ request("/rt/getInfo4", res4 -> Assertions.assertEquals(res4.getCode(), 204));
+
+ // getInfo5
+ request("/rt/getInfo5", res5 -> Assertions.assertEquals(res5.getCode(), 205));
+
+ // getInfo6
+ request("/rt/getInfo6", res6 -> Assertions.assertEquals(res6.getCode(), 206));
+
+ // getInfo7
+ request("/rt/getInfo7", res7 -> Assertions.assertEquals(res7.getCode(), 200));
+
+ // getInfo8
+ request("/rt/getInfo8", res8 -> Assertions.assertEquals(res8.getCode(), 200));
+
+ // getInfo9
+ request("/rt/getInfo9", res9 -> Assertions.assertEquals(res9.getCode(), 209));
+
+ // getInfo10
+ request("/rt/getInfo10", res10 -> Assertions.assertEquals(res10.getCode(), 200));
+
+ // getInfo11
+ request("/rt/getInfo11", res11 -> Assertions.assertEquals(res11.getCode(), 211));
+
+ // getInfo12
+ request("/rt/getInfo12", res12 -> Assertions.assertEquals(res12.getCode(), 212));
+
+ // getInfo13
+ request("/rt/getInfo13", res13 -> Assertions.assertEquals(res13.getCode(), 213));
+
+ // getInfo14
+ request("/rt/getInfo14", res14 -> Assertions.assertEquals(res14.getCode(), 214));
+
+ // getInfo15
+ request("/rt/getInfo15", res15 -> Assertions.assertEquals(res15.getCode(), 215));
+
+ }
+
+ // 测试 getUrl()
+ @Test
+ public void testGetUrl() {
+ // getInfo_101
+ request("/rt/getInfo_101", res -> Assertions.assertTrue(res.getData().toString().endsWith("/rt/getInfo_101")));
+
+ // getInfo_101,不包括后面的参数
+ request("/rt/getInfo_101?id=1", res2 -> Assertions.assertTrue(res2.getData().toString().endsWith("/rt/getInfo_101")));
+
+ // 自定义当前域名
+ SaManager.getConfig().setCurrDomain("http://xxx.com");
+ request("/rt/getInfo_101?id=1",
+ res3 -> Assertions.assertEquals(res3.getData().toString(), "http://xxx.com/rt/getInfo_101"));
+ SaManager.getConfig().setCurrDomain(null);
+ }
+
+ // 测试读取Cookie
+ @Test
+ public void testGetCookie() throws Exception {
+ request("/rt/getInfo_102", Map.of(), Map.of("x-token", "token-111"), res -> {
+ Assertions.assertEquals(res.getData(), "token-111");
+ }).statusCode(200);
+
+ }
+
+ // 测试重定向
+ @Test
+ public void testRedirect() throws Exception {
+ request("/rt/getInfo16", res -> {
+ }).statusCode(302).header("Location", "/rt/getInfo3");
+ }
+
+ // 空接口
+ @Test
+ public void testGetInfo200() {
+ request("/rt/getInfo_200", res -> Assertions.assertEquals(res.getCode(), 200));
+ request("/rt/getInfo_201", res1 -> Assertions.assertEquals(res1.getCode(), 201));
+ request("/rt/getInfo_202", res2 -> Assertions.assertEquals(res2.getCode(), 401));
+
+ // 登录拿到Token
+ request("/rt/login?id=10001", resLogin -> {
+ String satoken = resLogin.get("token", String.class);
+ request("/rt/getInfo_202?satoken=" + satoken, res3 -> Assertions.assertEquals(res3.getCode(), 200));
+ ;
+ });
+
+ }
+
+ // 测试转发
+ @Test
+ public void testForward() {
+ request("/rt/getInfo_103", res -> Assertions.assertEquals(res.getCode(), 200));
+
+ }
+
+ public static class RouteTestProfile implements QuarkusTestProfile {
+ public RouteTestProfile() {
+ }
+
+ public String getConfigProfile() {
+ return "route";
+ }
+ }
+}
diff --git a/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaAnnotationResourceTest.java b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaAnnotationResourceTest.java
new file mode 100644
index 0000000..60a5a80
--- /dev/null
+++ b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaAnnotationResourceTest.java
@@ -0,0 +1,118 @@
+package io.quarkiverse.satoken.resteasy.integrate;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import io.quarkiverse.satoken.resteasy.AbstractRequestTest;
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+
+/**
+ * SaAnnotationResteasyResourceTest
+ *
+ * @author nayan
+ * @date 2022/10/8 14:11
+ */
+@QuarkusTest
+@TestProfile(SaAnnotationResourceTest.AnnotationTestProfile.class)
+public class SaAnnotationResourceTest extends AbstractRequestTest {
+
+ // 校验通过的情况
+ @Test
+ public void testPassing() {
+ // 登录拿到Token
+ request("/at/login?id=10001", res -> {
+ String satoken = res.get("token", String.class);
+ Assertions.assertNotNull(satoken);
+
+ // 登录校验,通过
+ request("/at/checkLogin?satoken=" + satoken, res2 -> Assertions.assertEquals(res2.getCode(), 200));
+
+ // 角色校验,通过
+ request("/at/checkRole?satoken=" + satoken, res3 -> Assertions.assertEquals(res3.getCode(), 200));
+
+ // 权限校验,通过
+ request("/at/checkPermission?satoken=" + satoken, res4 -> Assertions.assertEquals(res4.getCode(), 200));
+
+ // 权限校验or角色校验,通过
+ request("/at/checkPermission2?satoken=" + satoken, res5 -> Assertions.assertEquals(res5.getCode(), 200));
+
+ // 开启二级认证
+ request("/at/openSafe?satoken=" + satoken, res6 -> Assertions.assertEquals(res6.getCode(), 200));
+
+ // 校验二级认证,通过
+ request("/at/checkSafe?satoken=" + satoken, res7 -> Assertions.assertEquals(res7.getCode(), 200));
+
+ // 访问校验封禁的接口 ,通过
+ request("/at/checkDisable?satoken=" + satoken, res9 -> Assertions.assertEquals(res9.getCode(), 200));
+ });
+
+ }
+
+ // 校验不通过的情况
+ @Test
+ public void testNotPassing() {
+ // 登录拿到Token
+
+ request("/at/login?id=10002", res -> {
+ String satoken = res.get("token", String.class);
+ Assertions.assertNotNull(satoken);
+
+ // 登录校验,不通过
+ request("/at/checkLogin", res2 -> Assertions.assertEquals(res2.getCode(), 401));
+
+ // 角色校验,不通过
+ request("/at/checkRole?satoken=" + satoken, res3 -> Assertions.assertEquals(res3.getCode(), 402));
+
+ // 权限校验,不通过
+ request("/at/checkPermission?satoken=" + satoken, res4 -> Assertions.assertEquals(res4.getCode(), 403));
+
+ // 权限校验or角色校验,不通过
+ request("/at/checkPermission2?satoken=" + satoken, res5 -> Assertions.assertEquals(res5.getCode(), 403));
+
+ // 校验二级认证,不通过
+ request("/at/checkSafe?satoken=" + satoken, res7 -> Assertions.assertEquals(res7.getCode(), 901));
+
+ });
+
+ // -------- 登录拿到Token
+ request("/at/login?id=10042", res -> {
+ String satoken10042 = res.get("token", String.class);
+ Assertions.assertNotNull(satoken10042);
+
+ // 校验账号封禁 ,通过
+ request("/at/disable?id=10042", res8 -> Assertions.assertEquals(res8.getCode(), 200));
+
+ // 访问校验封禁的接口 ,不通过
+ request("/at/checkDisable?satoken=" + satoken10042, res9 -> Assertions.assertEquals(res9.getCode(), 904));
+
+ // 解封后就能访问了
+ request("/at/untieDisable?id=10042", result -> {
+ });
+ request("/at/checkDisable?satoken=" + satoken10042, res10 -> Assertions.assertEquals(res10.getCode(), 200));
+
+ });
+
+ }
+
+ // 测试忽略认证
+ @Test
+ public void testIgnore() {
+ // 必须登录才能访问的
+ request("/ig/show1", res1 -> Assertions.assertEquals(res1.getCode(), 401));
+
+ // 不登录也可以访问的
+ request("/ig/show2", res2 -> Assertions.assertEquals(res2.getCode(), 200));
+ }
+
+ public static class AnnotationTestProfile implements QuarkusTestProfile {
+ public AnnotationTestProfile() {
+ }
+
+ public String getConfigProfile() {
+ return "annotation";
+ }
+ }
+
+}
diff --git a/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaIdTokenResourceTest.java b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaIdTokenResourceTest.java
new file mode 100644
index 0000000..6d64b04
--- /dev/null
+++ b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/integrate/SaIdTokenResourceTest.java
@@ -0,0 +1,101 @@
+package io.quarkiverse.satoken.resteasy.integrate;
+
+import static io.restassured.RestAssured.given;
+
+import javax.ws.rs.core.MediaType;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.exception.IdTokenInvalidException;
+import cn.dev33.satoken.id.SaIdUtil;
+import io.quarkiverse.satoken.resteasy.AbstractRequestTest;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.http.Header;
+import io.restassured.response.ValidatableResponse;
+
+/**
+ * SaIdTokenResourceTest
+ *
+ * @author nayan
+ * @date 2022/10/8 14:29
+ */
+@QuarkusTest
+public class SaIdTokenResourceTest extends AbstractRequestTest {
+
+ // 获取信息
+ @Test
+ public void testGetInfo() {
+ String token = SaIdUtil.getToken();
+ // 加token,能调通
+ request("/id/getInfo", token, res -> {
+ Assertions.assertEquals(200, res.getCode());
+ });
+ // 不加token,不能调通
+ request("/id/getInfo", "xxx", res -> {
+ Assertions.assertEquals(902, res.getCode());
+ });
+
+ // 获取信息2
+ token = SaIdUtil.getTokenNh();
+ // 加token,能调通
+ request("/id/getInfo2", token, res -> {
+ Assertions.assertEquals(200, res.getCode());
+ });
+ // 不加token,不能调通
+ request("/id/getInfo2", "xxx", res -> {
+ Assertions.assertEquals(902, res.getCode());
+ });
+ }
+
+ // 基础测试
+ @Test
+ public void testApi() {
+ String token = SaIdUtil.getToken();
+
+ // 刷新一下,会有变化
+ SaIdUtil.refreshToken();
+ String token2 = SaIdUtil.getToken();
+ Assertions.assertNotEquals(token, token2);
+
+ // 旧token,变为次级token
+ String pastToken = SaIdUtil.getPastTokenNh();
+ Assertions.assertEquals(token, pastToken);
+
+ // dao中应该有值
+ String daoToken = SaManager.getSaTokenDao().get("satoken:var:id-token");
+ String daoToken2 = SaManager.getSaTokenDao().get("satoken:var:past-id-token");
+ Assertions.assertEquals(token2, daoToken);
+ Assertions.assertEquals(token, daoToken2);
+
+ // 新旧都有效
+ Assertions.assertTrue(SaIdUtil.isValid(token));
+ Assertions.assertTrue(SaIdUtil.isValid(token2));
+
+ // 空的不行
+ Assertions.assertFalse(SaIdUtil.isValid(null));
+ Assertions.assertFalse(SaIdUtil.isValid(""));
+
+ // 不抛出异常
+ Assertions.assertDoesNotThrow(() -> SaIdUtil.checkToken(token));
+ Assertions.assertDoesNotThrow(() -> SaIdUtil.checkToken(token2));
+
+ // 抛出异常
+ Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken(null));
+ Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken(""));
+ Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken("aaa"));
+ }
+
+ protected ValidatableResponse request(String path, String token, SaResultMatcher matcher) {
+ return given()
+ .when()
+ .header(new Header(SaIdUtil.ID_TOKEN, token))
+ .accept(MediaType.APPLICATION_JSON)
+ .post(path)
+ .then()
+ .body(matcher);
+
+ }
+
+}
diff --git a/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/utils/SoMap.java b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/utils/SoMap.java
new file mode 100644
index 0000000..6286644
--- /dev/null
+++ b/quarkus-satoken-plugins/quarkus-satoken-dao-redis-jackson/integration-tests/src/test/java/io/quarkiverse/satoken/resteasy/utils/SoMap.java
@@ -0,0 +1,788 @@
+package io.quarkiverse.satoken.resteasy.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Map< String, Object> 是最常用的一种Map类型,但是它写着麻烦
+ *
+ * 所以特封装此类,继承Map,进行一些扩展,可以让Map更灵活使用
+ *
+ * 最新:2020-12-10 新增部分构造方法
+ *
+ * @author kong
+ */
+public class SoMap extends LinkedHashMap {
+
+ private static final long serialVersionUID = 1L;
+
+ public SoMap() {
+ }
+
+ /**
+ * 以下元素会在isNull函数中被判定为Null,
+ */
+ public static final Object[] NULL_ELEMENT_ARRAY = { null, "" };
+ public static final List