diff --git a/README.md b/README.md
index 6c4f21f7..a2d9559e 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 <p align="center">
 	<img alt="logo" src="https://gitee.com/dromara/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
 </p>
-<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.26.0</h1>
+<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.27.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"></a>
diff --git a/mvn clean.bat b/mvn clean.bat
index 3714ac9b..a0ed0917 100644
--- a/mvn clean.bat	
+++ b/mvn clean.bat	
@@ -37,11 +37,11 @@ cd sa-token-demo-alone-redis
 call mvn clean
 cd ..
 
-cd sa-token-demo-sso1
+cd sa-token-demo-thymeleaf
 call mvn clean
 cd ..
 
-cd sa-token-demo-sso1-server
+cd sa-token-demo-sso-server
 call mvn clean
 cd ..
 
@@ -49,18 +49,10 @@ cd sa-token-demo-sso1-client
 call mvn clean
 cd ..
 
-cd sa-token-demo-sso2-server
-call mvn clean
-cd ..
-
 cd sa-token-demo-sso2-client
 call mvn clean
 cd ..
 
-cd sa-token-demo-sso3-server
-call mvn clean
-cd ..
-
 cd sa-token-demo-sso3-client
 call mvn clean
 cd ..
diff --git a/pom.xml b/pom.xml
index 2bcefbb5..e9676e79 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
     <groupId>cn.dev33</groupId>
     <artifactId>sa-token-parent</artifactId>
 	<packaging>pom</packaging>
-	<version>1.26.0</version>
+	<version>1.27.0</version>
 	
 	<!-- 项目介绍 -->
 	<name>sa-token</name>
@@ -36,7 +36,7 @@
 	
 	<!-- 一些属性 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
         <jdk.version>1.8</jdk.version>
 		<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
diff --git a/sa-token-core/pom.xml b/sa-token-core/pom.xml
index 2ab1dc05..f855acaa 100644
--- a/sa-token-core/pom.xml
+++ b/sa-token-core/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-parent</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java
index 942bd705..dec08014 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java
@@ -63,7 +63,7 @@ public interface SaTempInterface {
 	}
 
 	/**
-	 * 删除一个token
+	 * 删除一个 token
 	 * @param token 指定token 
 	 */
 	public default void deleteToken(String token) {
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java
index b3d98c99..6dd78669 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java
@@ -48,5 +48,13 @@ public class SaTempUtil {
 	public static long getTimeout(String token) {
 		return SaManager.getSaTemp().getTimeout(token);
 	}
+
+	/**
+	 * 删除一个 token 
+	 * @param token 指定token 
+	 */
+	public static void deleteToken(String token) {
+		SaManager.getSaTemp().deleteToken(token);
+	}
 	
 }
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 4f9562d9..059df9a0 100644
--- a/sa-token-demo/sa-token-demo-alone-redis/pom.xml
+++ b/sa-token-demo/sa-token-demo-alone-redis/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-jwt/pom.xml b/sa-token-demo/sa-token-demo-jwt/pom.xml
index b3258df1..98903cf0 100644
--- a/sa-token-demo/sa-token-demo-jwt/pom.xml
+++ b/sa-token-demo/sa-token-demo-jwt/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-oauth2-client/pom.xml b/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
index c3a7efcc..32718d4d 100644
--- a/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-oauth2-client/pom.xml
@@ -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.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 	
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-oauth2-server/pom.xml b/sa-token-demo/sa-token-demo-oauth2-server/pom.xml
index ec934aea..cf1e3d5f 100644
--- a/sa-token-demo/sa-token-demo-oauth2-server/pom.xml
+++ b/sa-token-demo/sa-token-demo-oauth2-server/pom.xml
@@ -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.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 	
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-quick-login/pom.xml b/sa-token-demo/sa-token-demo-quick-login/pom.xml
index ff180acf..985f5fdd 100644
--- a/sa-token-demo/sa-token-demo-quick-login/pom.xml
+++ b/sa-token-demo/sa-token-demo-quick-login/pom.xml
@@ -15,7 +15,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml
index ba2bbd36..6faefeed 100644
--- a/sa-token-demo/sa-token-demo-solon/pom.xml
+++ b/sa-token-demo/sa-token-demo-solon/pom.xml
@@ -9,7 +9,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-springboot/pom.xml b/sa-token-demo/sa-token-demo-springboot/pom.xml
index c746f7cb..4f62f1d9 100644
--- a/sa-token-demo/sa-token-demo-springboot/pom.xml
+++ b/sa-token-demo/sa-token-demo-springboot/pom.xml
@@ -17,7 +17,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-sso-server/pom.xml b/sa-token-demo/sa-token-demo-sso-server/pom.xml
index 7651b0b1..7606a62f 100644
--- a/sa-token-demo/sa-token-demo-sso-server/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso-server/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-sso1-client/pom.xml b/sa-token-demo/sa-token-demo-sso1-client/pom.xml
index 3215da41..a1330a67 100644
--- a/sa-token-demo/sa-token-demo-sso1-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso1-client/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-sso2-client/pom.xml b/sa-token-demo/sa-token-demo-sso2-client/pom.xml
index 39a7564c..6cac052c 100644
--- a/sa-token-demo/sa-token-demo-sso2-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso2-client/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-sso3-client/pom.xml b/sa-token-demo/sa-token-demo-sso3-client/pom.xml
index c1209af4..c7ad31ff 100644
--- a/sa-token-demo/sa-token-demo-sso3-client/pom.xml
+++ b/sa-token-demo/sa-token-demo-sso3-client/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-thymeleaf/pom.xml b/sa-token-demo/sa-token-demo-thymeleaf/pom.xml
index a576aa2b..da09a711 100644
--- a/sa-token-demo/sa-token-demo-thymeleaf/pom.xml
+++ b/sa-token-demo/sa-token-demo-thymeleaf/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-demo/sa-token-demo-webflux/pom.xml b/sa-token-demo/sa-token-demo-webflux/pom.xml
index ae7cf214..d53616ba 100644
--- a/sa-token-demo/sa-token-demo-webflux/pom.xml
+++ b/sa-token-demo/sa-token-demo-webflux/pom.xml
@@ -16,7 +16,7 @@
 	
 	<!-- 定义sa-token版本号 -->
 	<properties>
-		<sa-token-version>1.26.0</sa-token-version>
+		<sa-token-version>1.27.0</sa-token-version>
 	</properties>
 
 	<dependencies>
diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md
index bef14a9c..c986dca0 100644
--- a/sa-token-doc/doc/README.md
+++ b/sa-token-doc/doc/README.md
@@ -1,7 +1,7 @@
 <p align="center">
 	<img alt="logo" src="https://gitee.com/dromara/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
 </p>
-<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.26.0</h1>
+<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.27.0</h1>
 <h5 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h5>
 <p align="center">
 	<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html
index 59de49aa..ea38b4e7 100644
--- a/sa-token-doc/doc/index.html
+++ b/sa-token-doc/doc/index.html
@@ -61,7 +61,7 @@
 		</div>
 		
 		<script>
-			var saTokenTopVersion = '1.26.0';	// Sa-Token最新版本 
+			var saTokenTopVersion = '1.27.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 = {
diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md
index 4d5a4058..bd44fb93 100644
--- a/sa-token-doc/doc/start/download.md
+++ b/sa-token-doc/doc/start/download.md
@@ -101,6 +101,7 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}'
 		├── sa-token-quick-login                  // [插件] Sa-Token 快速注入登录页插件 
 		├── sa-token-alone-redis                  // [插件] Sa-Token 独立Redis插件,实现[权限缓存与业务缓存分离]
 		├── sa-token-oauth2                       // [插件] Sa-Token 实现 OAuth2.0 模块 
+		├── sa-token-dialect-thymeleaf            // [插件] Sa-Token 标签方言(Thymeleaf版)
 	├── sa-token-demo                         // [示例] Sa-Token 示例合集
 		├── sa-token-demo-springboot              // [示例] Sa-Token 整合 SpringBoot 
 		├── sa-token-demo-webflux                 // [示例] Sa-Token 整合 WebFlux 
@@ -108,6 +109,7 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}'
 		├── sa-token-demo-solon                   // [示例] Sa-Token 集成 Solon 
 		├── sa-token-demo-quick-login             // [示例] Sa-Token 集成 quick-login 模块 
 		├── sa-token-demo-alone-redis             // [示例] Sa-Token 集成 alone-redis 模块
+		├── sa-token-demo-thymeleaf               // [示例] Sa-Token 集成 Thymeleaf 标签方言
 		├── sa-token-demo-sso-server              // [示例] Sa-Token 集成 SSO单点登录-Server认证中心
 		├── sa-token-demo-sso1-client             // [示例] Sa-Token 集成 SSO单点登录-模式一 应用端 
 		├── sa-token-demo-sso2-client             // [示例] Sa-Token 集成 SSO单点登录-模式二 应用端
diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html
index afcc3fac..6819925e 100644
--- a/sa-token-doc/index.html
+++ b/sa-token-doc/index.html
@@ -46,7 +46,7 @@
 				<div class="content-box">
 					<div class="fenge"></div>
 					<!-- <img class="title-logo" src="./doc/logo.png" onclick="alert('别点我, 快去点star!')"> -->
-					<h1>Sa-Token<small>v1.26.0</small></h1>
+					<h1>Sa-Token<small>v1.27.0</small></h1>
 					<div class="sub-title">一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!</div>
 					<div class="btn-box">
 						<a href="https://github.com/dromara/sa-token" target="_blank">GitHub</a>
diff --git a/sa-token-plugin/pom.xml b/sa-token-plugin/pom.xml
index b632e9a2..9f71965e 100644
--- a/sa-token-plugin/pom.xml
+++ b/sa-token-plugin/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-parent</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>pom</packaging>
     
diff --git a/sa-token-plugin/sa-token-alone-redis/pom.xml b/sa-token-plugin/sa-token-alone-redis/pom.xml
index 7bd1a447..e800e4a6 100644
--- a/sa-token-plugin/sa-token-alone-redis/pom.xml
+++ b/sa-token-plugin/sa-token-alone-redis/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-dao-redis-jackson/pom.xml b/sa-token-plugin/sa-token-dao-redis-jackson/pom.xml
index e885e5fe..4b8af348 100644
--- a/sa-token-plugin/sa-token-dao-redis-jackson/pom.xml
+++ b/sa-token-plugin/sa-token-dao-redis-jackson/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-dao-redis/pom.xml b/sa-token-plugin/sa-token-dao-redis/pom.xml
index e87b11fd..fdd40a2f 100644
--- a/sa-token-plugin/sa-token-dao-redis/pom.xml
+++ b/sa-token-plugin/sa-token-dao-redis/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-dialect-thymeleaf/pom.xml b/sa-token-plugin/sa-token-dialect-thymeleaf/pom.xml
index d556f0de..e7ee0ed6 100644
--- a/sa-token-plugin/sa-token-dialect-thymeleaf/pom.xml
+++ b/sa-token-plugin/sa-token-dialect-thymeleaf/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-oauth2/pom.xml b/sa-token-plugin/sa-token-oauth2/pom.xml
index b9bb9a4e..18ac129b 100644
--- a/sa-token-plugin/sa-token-oauth2/pom.xml
+++ b/sa-token-plugin/sa-token-oauth2/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-quick-login/pom.xml b/sa-token-plugin/sa-token-quick-login/pom.xml
index 355b3890..d4d40de4 100644
--- a/sa-token-plugin/sa-token-quick-login/pom.xml
+++ b/sa-token-plugin/sa-token-quick-login/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-spring-aop/pom.xml b/sa-token-plugin/sa-token-spring-aop/pom.xml
index 565203b7..a821a8cc 100644
--- a/sa-token-plugin/sa-token-spring-aop/pom.xml
+++ b/sa-token-plugin/sa-token-spring-aop/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-plugin/sa-token-temp-jwt/pom.xml b/sa-token-plugin/sa-token-temp-jwt/pom.xml
index 9def8fa3..65a45284 100644
--- a/sa-token-plugin/sa-token-temp-jwt/pom.xml
+++ b/sa-token-plugin/sa-token-temp-jwt/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-plugin</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-starter/pom.xml b/sa-token-starter/pom.xml
index a73722be..97278c5f 100644
--- a/sa-token-starter/pom.xml
+++ b/sa-token-starter/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-parent</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>pom</packaging>
     
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml b/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
index 149e0d6c..5246f281 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-starter</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-starter/sa-token-servlet/pom.xml b/sa-token-starter/sa-token-servlet/pom.xml
index c86759d7..04e6bafb 100644
--- a/sa-token-starter/sa-token-servlet/pom.xml
+++ b/sa-token-starter/sa-token-servlet/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-starter</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml
index 639a7c8b..3e9205a4 100644
--- a/sa-token-starter/sa-token-solon-plugin/pom.xml
+++ b/sa-token-starter/sa-token-solon-plugin/pom.xml
@@ -7,7 +7,7 @@
     <parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-starter</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-starter/sa-token-spring-boot-starter/pom.xml b/sa-token-starter/sa-token-spring-boot-starter/pom.xml
index 12cfe954..572579d4 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/pom.xml
+++ b/sa-token-starter/sa-token-spring-boot-starter/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
         <groupId>cn.dev33</groupId>
         <artifactId>sa-token-starter</artifactId>
-        <version>1.26.0</version>
+        <version>1.27.0</version>
     </parent>
     <packaging>jar</packaging>
 
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/BasicsTest.java b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/BasicsTest.java
new file mode 100644
index 00000000..4258c241
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/BasicsTest.java
@@ -0,0 +1,367 @@
+package com.pj.test;
+
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.dev33.satoken.exception.DisableLoginException;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.session.SaSessionCustomUtil;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.temp.SaTempUtil;
+import cn.dev33.satoken.util.SaTokenConsts;
+
+/**
+ * Sa-Token 基础API测试 
+ * 
+ * <p> 注解详解参考: https://www.cnblogs.com/flypig666/p/11505277.html
+ * @author Auster 
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = StartUpApplication.class)
+public class BasicsTest {
+
+	// 持久化Bean 
+	static SaTokenDao dao;
+	
+	// 开始 
+	@BeforeClass
+    public static void beforeClass() {
+    	System.out.println("\n\n------------------------ 基础测试 star ...");
+    	dao = SaManager.getSaTokenDao();
+    }
+
+	// 结束 
+    @AfterClass
+    public static void afterClass() {
+    	System.out.println("\n\n------------------------ 基础测试 end ... \n");
+    }
+
+    // 测试:登录 
+    @Test
+    public void doLogin() {
+    	// 登录
+    	StpUtil.login(10001);
+    	String token = StpUtil.getTokenValue();
+    	
+    	// API 验证 
+    	Assert.assertTrue(StpUtil.isLogin());	
+    	Assert.assertNotNull(token);	// token不为null
+    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);	// loginId=10001 
+    	Assert.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE);	// 登录设备 
+    	
+    	// db数据 验证  
+    	// token存在 
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token), "10001");
+    	// Session 存在 
+    	SaSession session = dao.getSession("satoken:login:session:" + 10001);
+    	Assert.assertNotNull(session);
+    	Assert.assertEquals(session.getId(), "satoken:login:session:" + 10001);
+    	Assert.assertTrue(session.getTokenSignList().size() >= 1);
+    }
+    
+    // 测试:注销 
+    @Test
+    public void logout() {
+    	// 登录
+    	StpUtil.login(10001);
+    	String token = StpUtil.getTokenValue();
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token), "10001");
+    	
+    	// 注销
+    	StpUtil.logout();
+    	// token 应该被清除
+    	Assert.assertNull(dao.get("satoken:login:token:" + token));
+    	// Session 应该被清除 
+    	SaSession session = dao.getSession("satoken:login:session:" + 10001);
+    	Assert.assertNull(session);
+    }
+    
+    // 测试:Session会话 
+    @Test
+    public void testSession() {
+    	StpUtil.login(10001);
+    	
+    	// API 应该可以获取 Session 
+    	Assert.assertNotNull(StpUtil.getSession(false));
+    	
+    	// db中应该存在 Session
+    	SaSession session = dao.getSession("satoken:login:session:" + 10001);
+    	Assert.assertNotNull(session);
+    	
+    	// 存取值 
+    	session.set("name", "zhang");
+    	session.set("age", "18");
+    	Assert.assertEquals(session.get("name"), "zhang");
+    	Assert.assertEquals(session.getInt("age"), 18);
+    	Assert.assertEquals((int)session.getModel("age", int.class), 18);
+    	Assert.assertEquals((int)session.get("age", 20), 18);
+    	Assert.assertEquals((int)session.get("name2", 20), 20);
+    	Assert.assertEquals((int)session.get("name2", () -> 30), 30);
+    	session.clear();
+    	Assert.assertEquals(session.get("name"), null);
+    }
+    
+    // 测试:权限认证 
+    @Test
+    public void testCheckPermission() {
+    	StpUtil.login(10001);
+    	
+    	// 权限认证 
+    	Assert.assertTrue(StpUtil.hasPermission("user-add"));
+    	Assert.assertTrue(StpUtil.hasPermission("user-list"));
+    	Assert.assertTrue(StpUtil.hasPermission("user"));
+    	Assert.assertTrue(StpUtil.hasPermission("art-add"));
+    	Assert.assertFalse(StpUtil.hasPermission("get-user"));
+    	// and
+    	Assert.assertTrue(StpUtil.hasPermissionAnd("art-add", "art-get"));
+    	Assert.assertFalse(StpUtil.hasPermissionAnd("art-add", "comment-add"));
+    	// or 
+    	Assert.assertTrue(StpUtil.hasPermissionOr("art-add", "comment-add"));
+    	Assert.assertFalse(StpUtil.hasPermissionOr("comment-add", "comment-delete"));
+    }
+
+    // 测试:角色认证
+    @Test
+    public void testCheckRole() {
+    	StpUtil.login(10001);
+    	
+    	// 角色认证 
+    	Assert.assertTrue(StpUtil.hasRole("admin")); 
+    	Assert.assertFalse(StpUtil.hasRole("teacher")); 
+    	// and
+    	Assert.assertTrue(StpUtil.hasRoleAnd("admin", "super-admin")); 
+    	Assert.assertFalse(StpUtil.hasRoleAnd("admin", "ceo")); 
+    	// or
+    	Assert.assertTrue(StpUtil.hasRoleOr("admin", "ceo")); 
+    	Assert.assertFalse(StpUtil.hasRoleOr("ceo", "cto")); 
+    }
+	
+    // 测试:根据token强制注销 
+    @Test
+    public void testLogoutByToken() {
+    	
+    	// 先登录上 
+    	StpUtil.login(10001); 
+    	Assert.assertTrue(StpUtil.isLogin());	
+    	String token = StpUtil.getTokenValue();
+    	
+    	// 根据token注销 
+    	StpUtil.logoutByTokenValue(token); 
+    	Assert.assertFalse(StpUtil.isLogin()); 
+    	
+    	// token 应该被清除
+    	Assert.assertNull(dao.get("satoken:login:token:" + token));
+    	// Session 应该被清除 
+    	SaSession session = dao.getSession("satoken:login:session:" + 10001);
+    	Assert.assertNull(session);
+
+		// 场景值应该是token无效 
+    	try {
+    		StpUtil.checkLogin();
+		} catch (NotLoginException e) {
+			Assert.assertEquals(e.getType(), NotLoginException.INVALID_TOKEN);
+		}
+    }
+
+    // 测试:根据账号id强制注销 
+    @Test
+    public void testLogoutByLoginId() {
+
+    	// 先登录上 
+    	StpUtil.login(10001); 
+    	Assert.assertTrue(StpUtil.isLogin());	
+    	String token = StpUtil.getTokenValue();
+    	
+    	// 根据账号id注销 
+    	StpUtil.logout(10001);
+    	Assert.assertFalse(StpUtil.isLogin()); 
+    	
+    	// token 应该被清除
+    	Assert.assertNull(dao.get("satoken:login:token:" + token));
+    	// Session 应该被清除 
+    	SaSession session = dao.getSession("satoken:login:session:" + 10001);
+    	Assert.assertNull(session);
+
+		// 场景值应该是token无效 
+    	try {
+    		StpUtil.checkLogin();
+		} catch (NotLoginException e) {
+			Assert.assertEquals(e.getType(), NotLoginException.INVALID_TOKEN);
+		}
+    }
+
+    // 测试Token-Session 
+    @Test
+    public void testTokenSession() {
+
+    	// 先登录上 
+    	StpUtil.login(10001); 
+    	String token = StpUtil.getTokenValue();
+    	
+    	// 刚开始不存在 
+    	Assert.assertNull(StpUtil.stpLogic.getTokenSession(false));
+    	SaSession session = dao.getSession("satoken:login:token-session:" + token);
+    	Assert.assertNull(session);
+    	
+    	// 调用一次就存在了 
+    	StpUtil.getTokenSession();
+    	Assert.assertNotNull(StpUtil.stpLogic.getTokenSession(false));
+    	SaSession session2 = dao.getSession("satoken:login:token-session:" + token);
+    	Assert.assertNotNull(session2);
+    }
+    
+    // 测试自定义Session 
+    @Test
+    public void testCustomSession() {
+    	// 刚开始不存在 
+    	Assert.assertFalse(SaSessionCustomUtil.isExists("art-1"));
+    	SaSession session = dao.getSession("satoken:custom:session:" + "art-1");
+    	Assert.assertNull(session);
+    	
+    	// 调用一下 
+    	SaSessionCustomUtil.getSessionById("art-1");
+    	
+    	// 就存在了 
+    	Assert.assertTrue(SaSessionCustomUtil.isExists("art-1"));
+    	SaSession session2 = dao.getSession("satoken:custom:session:" + "art-1");
+    	Assert.assertNotNull(session2);
+    	
+    	// 给删除掉 
+    	SaSessionCustomUtil.deleteSessionById("art-1");
+    	
+    	// 就又不存在了 
+    	Assert.assertFalse(SaSessionCustomUtil.isExists("art-1"));
+    	SaSession session3 = dao.getSession("satoken:custom:session:" + "art-1");
+    	Assert.assertNull(session3);
+    }
+    
+    // 测试:根据账号id踢人
+    @Test
+    public void kickoutByLoginId() {
+
+    	// 踢人下线 
+    	StpUtil.login(10001); 
+    	String token = StpUtil.getTokenValue();
+    	StpUtil.kickout(10001);
+    	
+    	// token 应该被打标记 
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token), NotLoginException.KICK_OUT);
+
+		// 场景值应该是token已被踢下线 
+    	try {
+    		StpUtil.checkLogin();
+		} catch (NotLoginException e) {
+			Assert.assertEquals(e.getType(), NotLoginException.KICK_OUT);
+		}
+    }
+    
+    // 测试:账号封禁 
+    @Test(expected = DisableLoginException.class)
+    public void testDisable() {
+    	
+    	// 封号 
+    	StpUtil.disable(10007, 200);
+    	Assert.assertTrue(StpUtil.isDisable(10007));
+    	Assert.assertEquals(dao.get("satoken:login:disable:" + 10007), DisableLoginException.BE_VALUE); 
+    	
+    	// 解封  
+    	StpUtil.untieDisable(10007);
+    	Assert.assertFalse(StpUtil.isDisable(10007));
+    	Assert.assertEquals(dao.get("satoken:login:disable:" + 10007), null); 
+    	
+    	// 封号后登陆 (会抛出 DisableLoginException 异常)
+    	StpUtil.disable(10007, 200); 
+    	StpUtil.login(10007);  
+    }
+
+    // 测试:身份切换 
+    @Test
+    public void testSwitch() {
+    	// 登录
+    	StpUtil.login(10001);
+    	Assert.assertFalse(StpUtil.isSwitch());
+    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);
+    	
+    	// 开始身份切换 
+    	StpUtil.switchTo(10044);
+    	Assert.assertTrue(StpUtil.isSwitch());
+    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10044);
+    	
+    	// 结束切换 
+    	StpUtil.endSwitch(); 
+    	Assert.assertFalse(StpUtil.isSwitch());
+    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);
+    }
+    
+    // 测试:会话管理
+    @Test
+    public void testSearchTokenValue() {
+    	// 登录
+    	StpUtil.login(10001);
+    	StpUtil.login(10002);
+    	StpUtil.login(10003);
+    	StpUtil.login(10004);
+    	StpUtil.login(10005);
+    	
+    	// 查询 
+    	List<String> list = StpUtil.searchTokenValue("", 0, 10);
+    	Assert.assertTrue(list.size() >= 5);
+    }
+    
+    // 测试:临时Token认证模块
+    @Test
+    public void testSaTemp() {
+    	// 生成token 
+    	String token = SaTempUtil.createToken("group-1014", 200);
+    	Assert.assertNotNull(token);
+    	
+    	// 解析token  
+    	String value = SaTempUtil.parseToken(token, String.class);
+    	Assert.assertEquals(value, "group-1014"); 
+    	Assert.assertEquals(dao.getObject("satoken:temp-token:" + token), "group-1014");
+    	
+    	// 过期时间 
+    	long timeout = SaTempUtil.getTimeout(token);
+    	Assert.assertTrue(timeout > 195);
+    	
+    	// 回收token 
+    	SaTempUtil.deleteToken(token);
+    	String value2 = SaTempUtil.parseToken(token, String.class);
+    	Assert.assertEquals(value2, null); 
+    	Assert.assertEquals(dao.getObject("satoken:temp-token:" + token), null);
+    }
+
+    // 测试:二级认证
+    @Test
+    public void testSafe() {
+    	// 登录 
+    	StpUtil.login(10001);
+    	Assert.assertFalse(StpUtil.isSafe());
+    	
+    	// 开启二级认证 
+    	StpUtil.openSafe(2);
+    	Assert.assertTrue(StpUtil.isSafe()); 
+    	Assert.assertTrue(StpUtil.getSafeTime() > 0); 
+    	
+    	// 自然结束 
+//    	Thread.sleep(2500);
+//    	Assert.assertFalse(StpUtil.isSafe());
+    	
+    	// 手动结束
+//    	StpUtil.openSafe(2);
+    	StpUtil.closeSafe();
+    	Assert.assertFalse(StpUtil.isSafe());
+    }
+    
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/ManyLoginTest.java b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/ManyLoginTest.java
new file mode 100644
index 00000000..8789ca0b
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/ManyLoginTest.java
@@ -0,0 +1,164 @@
+package com.pj.test;
+
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.config.SaTokenConfig;
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.dev33.satoken.session.TokenSign;
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Sa-Token 多端登录测试 
+ * 
+ * @author kong 
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = StartUpApplication.class)
+public class ManyLoginTest {
+
+	// 持久化Bean 
+	static SaTokenDao dao;
+	
+	// 开始 
+	@BeforeClass
+    public static void beforeClass() {
+    	System.out.println("\n------------ 多端登录测试 star ...");
+    	dao = SaManager.getSaTokenDao();
+    }
+	// 结束 
+    @AfterClass
+    public static void afterClass() {
+//    	System.out.println("\n---------- 多端登录测试 end ... \n");
+    }
+
+    // 测试:并发登录、共享token、同端 
+    @Test
+    public void login() {
+    	SaManager.setConfig(new SaTokenConfig());
+    	
+    	StpUtil.login(10001);
+    	String token1 = StpUtil.getTokenValue();
+
+    	StpUtil.login(10001);
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	Assert.assertEquals(token1, token2);
+    }
+
+    // 测试:并发登录、共享token、不同端 
+    @Test
+    public void login2() {
+    	SaManager.setConfig(new SaTokenConfig());
+    	
+    	StpUtil.login(10001, "APP");
+    	String token1 = StpUtil.getTokenValue();
+
+    	StpUtil.login(10001, "PC");
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	Assert.assertNotEquals(token1, token2);
+    }
+
+    // 测试:并发登录、不共享token
+    @Test
+    public void login3() {
+    	SaManager.setConfig(new SaTokenConfig().setIsShare(false));
+    	
+    	StpUtil.login(10001);
+    	String token1 = StpUtil.getTokenValue();
+
+    	StpUtil.login(10001);
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	Assert.assertNotEquals(token1, token2);
+    }
+
+    // 测试:禁并发登录,后者顶出前者 
+    @Test
+    public void login4() {
+    	SaManager.setConfig(new SaTokenConfig().setIsConcurrent(false));
+    	
+    	StpUtil.login(10001);
+    	String token1 = StpUtil.getTokenValue();
+
+    	StpUtil.login(10001);
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	// token不同 
+    	Assert.assertNotEquals(token1, token2);
+    	
+    	// token1会被标记为:已被顶下线 
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token1), "-4");
+    	
+    	// User-Session里的 token1 签名会被移除 
+    	List<TokenSign> tokenSignList = StpUtil.getSessionByLoginId(10001).getTokenSignList();
+    	for (TokenSign tokenSign : tokenSignList) {
+    		Assert.assertNotEquals(tokenSign.getValue(), token1);
+		}
+    }
+    
+    // 测试:多端登录,一起强制注销 
+    @Test
+    public void login5() {
+    	SaManager.setConfig(new SaTokenConfig());
+    	
+    	StpUtil.login(10001, "APP");
+    	String token1 = StpUtil.getTokenValue();
+    	
+    	StpUtil.login(10001, "PC");
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	StpUtil.login(10001, "h5");
+    	String token3 = StpUtil.getTokenValue();
+    	
+    	// 注销 
+    	StpUtil.logout(10001);
+
+    	// 三个Token应该全部无效 
+    	Assert.assertNull(dao.get("satoken:login:token:" + token1));
+    	Assert.assertNull(dao.get("satoken:login:token:" + token2));
+    	Assert.assertNull(dao.get("satoken:login:token:" + token3));
+    	
+    	// User-Session也应该被清除掉 
+    	Assert.assertNull(StpUtil.getSessionByLoginId(10001, false));
+    	Assert.assertNull(dao.getSession("satoken:login:session:" + 10001));
+    }
+
+    // 测试:多端登录,一起强制踢下线 
+    @Test
+    public void login6() {
+    	SaManager.setConfig(new SaTokenConfig());
+    	
+    	StpUtil.login(10001, "APP");
+    	String token1 = StpUtil.getTokenValue();
+    	
+    	StpUtil.login(10001, "PC");
+    	String token2 = StpUtil.getTokenValue();
+    	
+    	StpUtil.login(10001, "h5");
+    	String token3 = StpUtil.getTokenValue();
+    	
+    	// 注销 
+    	StpUtil.kickout(10001);
+
+    	// 三个Token应该全部无效 
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token1), "-5");
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token2), "-5");
+    	Assert.assertEquals(dao.get("satoken:login:token:" + token3), "-5");
+    	
+    	// User-Session也应该被清除掉 
+    	Assert.assertNull(StpUtil.getSessionByLoginId(10001, false));
+    	Assert.assertNull(dao.getSession("satoken:login:session:" + 10001));
+    }
+    
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java
deleted file mode 100644
index 122c4de0..00000000
--- a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package com.pj.test;
-
-import java.util.List;
-
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import cn.dev33.satoken.exception.DisableLoginException;
-import cn.dev33.satoken.session.SaSession;
-import cn.dev33.satoken.stp.StpUtil;
-import cn.dev33.satoken.temp.SaTempUtil;
-import cn.dev33.satoken.util.SaTokenConsts;
-
-/**
- * Sa-Token 单元测试 
- * 
- * <p> 注解详解参考: https://www.cnblogs.com/flypig666/p/11505277.html
- * @author Auster 
- *
- */
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = StartUpApplication.class)
-public class SaTokenSpringBootStarterTest {
-
-	// 开始 
-	@BeforeClass
-    public static void beforeClass() {
-    	System.out.println("\n\n------------------------ Test star ...");
-    }
-
-	// 结束 
-    @AfterClass
-    public static void afterClass() {
-    	System.out.println("\n\n------------------------ Test end ... \n");
-    }
-
-    // 测试:登录 & 注销 
-    @Test
-    public void testDoLogin() {
-    	// 登录
-    	StpUtil.login(10001);
-    	Assert.assertTrue(StpUtil.isLogin());	
-    	Assert.assertNotNull(StpUtil.getTokenValue());	// token不为null
-    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);	// loginId=10001 
-    	Assert.assertEquals(StpUtil.getLoginDevice(), SaTokenConsts.DEFAULT_LOGIN_DEVICE);	// 登录设备 
-    	
-    	// 注销
-    	StpUtil.logout();
-    	Assert.assertFalse(StpUtil.isLogin());
-    	// Assert.assertNull(StpUtil.getTokenValue());
-    	Assert.assertNull(StpUtil.getLoginIdDefaultNull()); 
-    }
-
-    // 测试:权限认证 
-    @Test
-    public void testCheckPermission() {
-    	StpUtil.login(10001);
-    	
-    	// 权限认证 
-    	Assert.assertTrue(StpUtil.hasPermission("user-add"));
-    	Assert.assertTrue(StpUtil.hasPermission("user-list"));
-    	Assert.assertTrue(StpUtil.hasPermission("user"));
-    	Assert.assertTrue(StpUtil.hasPermission("art-add"));
-    	Assert.assertFalse(StpUtil.hasPermission("get-user"));
-    }
-
-    // 测试:角色认证
-    @Test
-    public void testCheckRole() {
-    	StpUtil.login(10001);
-    	
-    	// 角色认证 
-    	Assert.assertTrue(StpUtil.hasRole("admin")); 
-    	Assert.assertFalse(StpUtil.hasRole("teacher")); 
-    }
-	
-    // 测试:踢人下线 
-    @Test
-    public void testKickOut() {
-    	
-    	// 根据token踢人 
-    	StpUtil.login(10001); 
-    	Assert.assertTrue(StpUtil.isLogin());	
-    	StpUtil.logoutByTokenValue(StpUtil.getTokenValue()); 
-    	Assert.assertFalse(StpUtil.isLogin()); 
-
-    	// 根据账号id踢人
-    	StpUtil.login(10001); 
-    	Assert.assertTrue(StpUtil.isLogin());	
-    	StpUtil.kickout(10001);
-    	Assert.assertFalse(StpUtil.isLogin()); 
-    }
-
-    // 测试:账号封禁 
-    @Test(expected = DisableLoginException.class)
-    public void testDisable() {
-    	
-    	// 封号 
-    	StpUtil.disable(10007, 200);
-    	Assert.assertTrue(StpUtil.isDisable(10007));
-    	
-    	// 解封  
-    	StpUtil.untieDisable(10007);
-    	Assert.assertFalse(StpUtil.isDisable(10007));
-    	
-    	// 封号后登陆 (会抛出 DisableLoginException 异常)
-    	StpUtil.disable(10007, 200); 
-    	StpUtil.login(10007);  
-    }
-
-    // 测试:Session会话 
-    @Test
-    public void testSession() {
-    	StpUtil.login(10001);
-    	
-    	// Session 应该存在 
-    	Assert.assertNotNull(StpUtil.getSession(false));
-    	
-    	// 存取值 
-    	SaSession session = StpUtil.getSession();
-    	session.set("name", "zhang");
-    	session.set("age", "18");
-    	Assert.assertEquals(session.get("name"), "zhang");
-    	Assert.assertEquals(session.getInt("age"), 18);
-    	Assert.assertEquals((int)session.getModel("age", int.class), 18);
-    	Assert.assertEquals((int)session.get("age", 20), 18);
-    	Assert.assertEquals((int)session.get("name2", 20), 20);
-    	Assert.assertEquals((int)session.get("name2", () -> 30), 30);
-    	
-    }
-    
-    // 测试:身份切换 
-    @Test
-    public void testSwitch() {
-    	// 登录
-    	StpUtil.login(10001);
-    	Assert.assertFalse(StpUtil.isSwitch());
-    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);
-    	
-    	// 开始身份切换 
-    	StpUtil.switchTo(10044);
-    	Assert.assertTrue(StpUtil.isSwitch());
-    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10044);
-    	
-    	// 结束切换 
-    	StpUtil.endSwitch(); 
-    	Assert.assertFalse(StpUtil.isSwitch());
-    	Assert.assertEquals(StpUtil.getLoginIdAsLong(), 10001);
-    }
-    
-    // 测试:会话管理
-    @Test
-    public void testSearchTokenValue() {
-    	// 登录
-    	StpUtil.login(10001);
-    	StpUtil.login(10002);
-    	StpUtil.login(10003);
-    	StpUtil.login(10004);
-    	StpUtil.login(10005);
-    	
-    	// 查询 
-    	List<String> list = StpUtil.searchTokenValue("", 0, 10);
-    	Assert.assertTrue(list.size() >= 5);
-    }
-    
-    // 测试:临时验证模块
-    @Test
-    public void testSaTemp() {
-    	// 生成token 
-    	String token = SaTempUtil.createToken("group-1014", 200);
-    	Assert.assertNotNull(token);
-    	
-    	// 解析token  
-    	String value = SaTempUtil.parseToken(token, String.class);
-    	Assert.assertEquals(value, "group-1014"); 
-    	
-    	// 过期时间 
-    	long timeout = SaTempUtil.getTimeout(token);
-    	Assert.assertTrue(timeout > 195);
-    }
-
-    // 测试:二级认证
-    @Test
-    public void testSafe() throws InterruptedException {
-    	// 登录 
-    	StpUtil.login(10001);
-    	Assert.assertFalse(StpUtil.isSafe());
-    	
-    	// 开启二级认证 
-    	StpUtil.openSafe(2);
-    	Assert.assertTrue(StpUtil.isSafe()); 
-    	Assert.assertTrue(StpUtil.getSafeTime() > 0); 
-    	
-    	// 自然结束 
-    	Thread.sleep(2500);
-    	Assert.assertFalse(StpUtil.isSafe());
-    	
-    	// 手动结束
-    	StpUtil.openSafe(2);
-    	StpUtil.closeSafe();
-    	Assert.assertFalse(StpUtil.isSafe());
-    }
-    
-}