1
0
mirror of synced 2026-05-22 14:43:15 +00:00
This commit is contained in:
click33
2023-06-21 17:13:36 +08:00
747 changed files with 21599 additions and 13079 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.34.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.34.1</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>
+38 -8
View File
@@ -8,8 +8,6 @@ cd sa-token-demo
cd sa-token-demo-alone-redis & call mvn clean & cd ..
cd sa-token-demo-alone-redis-cluster & call mvn clean & cd ..
cd sa-token-demo-case & call mvn clean & cd ..
cd sa-token-demo-dubbo-consumer & call mvn clean & cd ..
cd sa-token-demo-dubbo-provider & call mvn clean & cd ..
cd sa-token-demo-grpc & call mvn clean & cd ..
cd sa-token-demo-jwt & call mvn clean & cd ..
cd sa-token-demo-oauth2-client & call mvn clean & cd ..
@@ -22,17 +20,49 @@ cd sa-token-demo-springboot3-redis & call mvn clean & cd ..
cd sa-token-demo-springboot-redis & call mvn clean & cd ..
cd sa-token-demo-springboot-redisson & call mvn clean & cd ..
cd sa-token-demo-test & call mvn clean & cd ..
cd sa-token-demo-sso1-client & call mvn clean & cd ..
cd sa-token-demo-sso2-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client-nosdk & call mvn clean & cd ..
cd sa-token-demo-sso-server & call mvn clean & cd ..
cd sa-token-demo-sso-server-solon & call mvn clean & cd ..
cd sa-token-demo-thymeleaf & call mvn clean & cd ..
cd sa-token-demo-webflux & call mvn clean & cd ..
cd sa-token-demo-webflux-springboot3 & call mvn clean & cd ..
cd sa-token-demo-websocket & call mvn clean & cd ..
cd sa-token-demo-websocket-spring & call mvn clean & cd ..
cd sa-token-demo-bom-import & call mvn clean & cd ..
cd sa-token-demo-sso
cd sa-token-demo-sso-server & call mvn clean & cd ..
cd sa-token-demo-sso1-client & call mvn clean & cd ..
cd sa-token-demo-sso2-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client & call mvn clean & cd ..
cd sa-token-demo-sso3-client-nosdk & call mvn clean & cd ..
cd ..
cd sa-token-demo-sso-for-solon
cd sa-token-demo-sso1-client-solon & call mvn clean & cd ..
cd sa-token-demo-sso2-client-solon & call mvn clean & cd ..
cd sa-token-demo-sso3-client-solon & call mvn clean & cd ..
cd sa-token-demo-sso-server-solon & call mvn clean & cd ..
cd ..
cd sa-token-demo-oauth2
cd sa-token-demo-oauth2-client & call mvn clean & cd ..
cd sa-token-demo-oauth2-server & call mvn clean & cd ..
cd ..
cd sa-token-demo-dubbo
cd sa-token-demo-dubbo-consumer & call mvn clean & cd ..
cd sa-token-demo-dubbo-provider & call mvn clean & cd ..
cd sa-token-demo-dubbo3-consumer & call mvn clean & cd ..
cd sa-token-demo-dubbo3-provider & call mvn clean & cd ..
cd ..
cd sa-token-demo-remember-me
cd server_project & call mvn clean & cd ..
cd ..
cd ..
+3 -6
View File
@@ -19,16 +19,13 @@
<!-- 所有模块 -->
<modules>
<module>sa-token-dependencies</module>
<module>sa-token-bom</module>
<module>sa-token-core</module>
<module>sa-token-starter</module>
<module>sa-token-plugin</module>
<module>sa-token-demo/sa-token-demo-sso-server-solon</module>
<module>sa-token-demo/sa-token-demo-sso1-client-solon</module>
<module>sa-token-demo/sa-token-demo-sso2-client-solon</module>
<module>sa-token-demo/sa-token-demo-sso3-client-solon</module>
</modules>
<!-- 开源协议 apache 2.0 -->
<!-- 开源协议 apache 2.0 -->
<licenses>
<license>
<name>Apache 2</name>
@@ -40,7 +37,7 @@
<!-- 一些属性 -->
<properties>
<revision>1.34.0</revision>
<revision>1.34.1</revision>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
+171
View File
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-bom</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>sa-token-bom</name>
<description>Sa-Token Bom</description>
<properties>
<revision>1.34.1</revision>
</properties>
<dependencyManagement>
<dependencies>
<!-- sa-token 核心 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${revision}</version>
</dependency>
<!-- region sa-token-starter -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jboot-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jfinal-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-servlet</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jakarta-servlet</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-solon-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-autoconfig</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${revision}</version>
</dependency>
<!-- endregion-->
<!-- region sa-token-plugin -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-alone-redis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dubbo</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-grpc</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-fastjson</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-fastjson2</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisx</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dialect-thymeleaf</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-oauth2</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-quick-login</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-aop</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-temp-jwt</artifactId>
<version>${revision}</version>
</dependency>
<!-- endregion-->
</dependencies>
</dependencyManagement>
</project>
@@ -1,8 +1,20 @@
/*
* 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;
import java.util.LinkedHashMap;
import java.util.Map;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.context.SaTokenContext;
@@ -19,24 +31,28 @@ import cn.dev33.satoken.log.SaLog;
import cn.dev33.satoken.log.SaLogForConsole;
import cn.dev33.satoken.same.SaSameTemplate;
import cn.dev33.satoken.sign.SaSignTemplate;
import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.temp.SaTempDefaultImpl;
import cn.dev33.satoken.temp.SaTempInterface;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 管理 Sa-Token 所有全局组件
* @author kong
* 管理 Sa-Token 所有全局组件,可通过此类快速获取、写入各种全局组件对象
*
* @author click33
* @since 1.18.0
*/
public class SaManager {
/**
* 配置文件 Bean
* 全局配置对象
*/
public volatile static SaTokenConfig config;
public static void setConfig(SaTokenConfig config) {
@@ -46,16 +62,26 @@ public class SaManager {
if(config !=null && config.getIsPrint()) {
SaFoxUtil.printSaToken();
}
// 如果此 config 对象没有配置 isColorLog 的值,则框架为它自动判断一下
if(config != null && config.getIsLog() != null && config.getIsLog() && config.getIsColorLog() == null) {
config.setIsColorLog(SaFoxUtil.isCanColorLog());
}
// $$ 全局事件
SaTokenEventCenter.doSetConfig(config);
// 调用一次StpUtil中的方法,保证其可以尽早的初始化 StpLogic
// 调用一次 StpUtil 中的方法,保证其可以尽早的初始化 StpLogic
StpUtil.getLoginType();
}
private static void setConfigMethod(SaTokenConfig config) {
SaManager.config = config;
}
/**
* 获取 Sa-Token 的全局配置信息
* @return 全局配置信息
*/
public static SaTokenConfig getConfig() {
if (config == null) {
synchronized (SaManager.class) {
@@ -68,7 +94,7 @@ public class SaManager {
}
/**
* 持久化 Bean
* 持久化组件
*/
private volatile static SaTokenDao saTokenDao;
public static void setSaTokenDao(SaTokenDao saTokenDao) {
@@ -93,7 +119,7 @@ public class SaManager {
}
/**
* 权限认证 Bean
* 权限数据源组件
*/
private volatile static StpInterface stpInterface;
public static void setStpInterface(StpInterface stpInterface) {
@@ -112,7 +138,7 @@ public class SaManager {
}
/**
* 上下文Context Bean
* 一级上下文 SaTokenContextContext
*/
private volatile static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
@@ -124,7 +150,7 @@ public class SaManager {
}
/**
* 二级Context
* 二级上下文 SaTokenSecondContext
*/
private volatile static SaTokenSecondContext saTokenSecondContext;
public static void setSaTokenSecondContext(SaTokenSecondContext saTokenSecondContext) {
@@ -136,7 +162,7 @@ public class SaManager {
}
/**
* 获取一个可用的SaTokenContext
* 获取一个可用的 SaTokenContext (按照一级上下文、二级上下文、默认上下文的顺序来判断)
* @return /
*/
public static SaTokenContext getSaTokenContextOrSecond() {
@@ -160,7 +186,7 @@ public class SaManager {
}
/**
* 临时令牌验证模块 Bean
* 临时 token 认证模块
*/
private volatile static SaTempInterface saTemp;
public static void setSaTemp(SaTempInterface saTemp) {
@@ -179,7 +205,7 @@ public class SaManager {
}
/**
* JSON 转换器 Bean
* JSON 转换器
*/
private volatile static SaJsonTemplate saJsonTemplate;
public static void setSaJsonTemplate(SaJsonTemplate saJsonTemplate) {
@@ -198,7 +224,7 @@ public class SaManager {
}
/**
* 参数签名 Bean
* API 参数签名
*/
private volatile static SaSignTemplate saSignTemplate;
public static void setSaSignTemplate(SaSignTemplate saSignTemplate) {
@@ -209,7 +235,7 @@ public class SaManager {
if (saSignTemplate == null) {
synchronized (SaManager.class) {
if (saSignTemplate == null) {
SaManager.saSignTemplate = new SaSignTemplateDefaultImpl();
SaManager.saSignTemplate = new SaSignTemplate();
}
}
}
@@ -217,7 +243,7 @@ public class SaManager {
}
/**
* Same-Token Bean
* Same-Token 同源系统认证模块
*/
private volatile static SaSameTemplate saSameTemplate;
public static void setSaSameTemplate(SaSameTemplate saSameTemplate) {
@@ -248,9 +274,9 @@ public class SaManager {
}
/**
* StpLogic集合, 记录框架所有成功初始化的StpLogic
* StpLogic 集合, 记录框架所有成功初始化的 StpLogic
*/
public static Map<String, StpLogic> stpLogicMap = new LinkedHashMap<String, StpLogic>();
public static Map<String, StpLogic> stpLogicMap = new LinkedHashMap<>();
/**
* 向全局集合中 put 一个 StpLogic
@@ -260,6 +286,13 @@ public class SaManager {
stpLogicMap.put(stpLogic.getLoginType(), stpLogic);
}
/**
* 在全局集合中 移除 一个 StpLogic
*/
public static void removeStpLogic(String loginType) {
stpLogicMap.remove(loginType);
}
/**
* 根据 LoginType 获取对应的StpLogic,如果不存在则新建并返回
* @param loginType 对应的账号类型
@@ -270,7 +303,7 @@ public class SaManager {
}
/**
* 根据 LoginType 获取对应的StpLogic,如果不存在,isCreate参数=是否自动创建并返回
* 根据 LoginType 获取对应的StpLogic,如果不存在,isCreate = 是否自动创建并返回
* @param loginType 对应的账号类型
* @param isCreate 在 StpLogic 不存在时,true=新建并返回,false=抛出异常
* @return 对应的StpLogic
@@ -290,9 +323,7 @@ public class SaManager {
synchronized (SaManager.class) {
stpLogic = stpLogicMap.get(loginType);
if(stpLogic == null) {
stpLogic = new StpLogic(loginType);
// 此处无需手动put,因为 StpLogic 构造方法中会自动put
// putStpLogic(stpLogic);
stpLogic = SaStrategy.instance.createStpLogic.apply(loginType);
}
}
}
@@ -1,17 +1,34 @@
/*
* 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.annotation;
import cn.dev33.satoken.basic.SaBasicTemplate;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.dev33.satoken.basic.SaBasicTemplate;
/**
* Http Basic 认证校验:只有通过 Basic 认证后才能进入该方法
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* @author kong
* Http Basic 认证校验:只有通过 Http Basic 认证后才能进入该方法,否则抛出异常。
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.26.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@@ -19,13 +36,13 @@ public @interface SaCheckBasic {
/**
* 领域
* @return see note
* @return /
*/
String realm() default SaBasicTemplate.DEFAULT_REALM;
/**
* 需要校验的账号密码,格式形如 sa:123456
* @return see note
* @return /
*/
String account() default "";
@@ -1,38 +1,55 @@
/*
* 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.annotation;
import cn.dev33.satoken.util.SaTokenConsts;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 服务禁用校验:在没有被禁用指定服务的情况下才可以进入方法
* 服务禁用校验:判断当前账号是否被禁用指定服务,如果被禁用,会抛出异常,没有被禁用才能进入方法
*
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author videomonster
* @since 1.31.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckDisable {
/**
* 多账号体系下所属的账号体系标识
* @return see note
* 多账号体系下所属的账号体系标识,非多账号体系无需关注此值
*
* @return /
*/
String type() default "";
/**
* 服务标识 (要校验是否禁用的服务名称)
* 服务标识 具体你要校验是否禁用的服务名称)
*
* @return see note
* @return /
*/
String[] value() default { SaTokenConsts.DEFAULT_DISABLE_SERVICE };
/**
* 封禁等级(只有 封禁等级 ≥ 此值 才会抛出异常
* 封禁等级(如果当前账号的被封禁等级 ≥ 此值,请求就无法进入方法
*
* @return /
*/
@@ -1,3 +1,18 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
@@ -6,18 +21,21 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 登录认证校验:只有登录之后才能进入该方法
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* @author kong
* 登录认证校验:只有登录之后才能进入该方法
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.10.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckLogin {
/**
* 多账号体系下所属的账号体系标识
* @return see note
* 多账号体系下所属的账号体系标识,非多账号体系无需关注此值
*
* @return /
*/
String type() default "";
@@ -0,0 +1,77 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 批量注解鉴权:只要满足其中一个注解即可通过验证
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.35.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckOr {
/**
* 设定 @SaCheckLogin,参考 {@link SaCheckLogin}
*
* @return /
*/
SaCheckLogin[] login() default {};
/**
* 设定 @SaCheckPermission,参考 {@link SaCheckPermission}
*
* @return /
*/
SaCheckPermission[] permission() default {};
/**
* 设定 @SaCheckRole,参考 {@link SaCheckRole}
*
* @return /
*/
SaCheckRole[] role() default {};
/**
* 设定 @SaCheckSafe,参考 {@link SaCheckSafe}
*
* @return /
*/
SaCheckSafe[] safe() default {};
/**
* 设定 @SaCheckBasic,参考 {@link SaCheckBasic}
*
* @return /
*/
SaCheckBasic[] basic() default {};
/**
* 设定 @SaCheckDisable,参考 {@link SaCheckDisable}
*
* @return /
*/
SaCheckDisable[] disable() default {};
}
@@ -1,3 +1,18 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
@@ -6,44 +21,49 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 权限认证校验:必须具有指定权限才能进入该方法
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* @author kong
* 权限认证校验:必须具有指定权限才能进入该方法
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.10.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface SaCheckPermission {
/**
* 需要校验的权限码
* @return 需要校验的权限码
* 多账号体系下所属的账号体系标识,非多账号体系无需关注此值
*
* @return /
*/
String type() default "";
/**
* 需要校验的权限码 [ 数组 ]
*
* @return /
*/
String [] value() default {};
/**
* 验证模式:AND | OR,默认AND
* @return 验证模式
*
* @return /
*/
SaMode mode() default SaMode.AND;
/**
* 多账号体系下所属的账号体系标识
* @return see note
*/
String type() default "";
/**
* 在权限认证不通过时的次要选择,两者只要其一认证成功即可通过校验
* 在权限校验不通过时的次要选择,两者只要其一校验成功即可通过校验
*
* <p>
* 例1@SaCheckPermission(value="user-add", orRole="admin")
* 代表本次请求只要具有 user-add权限 或 admin角色 其一即可通过校验
* 代表本次请求只要具有 user-add权限 或 admin角色 其一即可通过校验
* </p>
*
* <p>
* 例2 orRole = {"admin", "manager", "staff"},具有三个角色其一即可 <br>
* 例3 orRole = {"admin, manager, staff"},必须三个角色同时具备
* 例2 orRole = {"admin", "manager", "staff"},具有三个角色其一即可 <br>
* 例3 orRole = {"admin, manager, staff"},必须三个角色同时具备
* </p>
*
* @return /
@@ -1,3 +1,18 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
@@ -6,32 +21,36 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 角色认证校验:必须具有指定角色标识才能进入该方法
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* @author kong
* 角色认证校验:必须具有指定角色标识才能进入该方法
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.10.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface SaCheckRole {
/**
* 需要校验的角色标识
* @return 需要校验的角色标识
* 多账号体系下所属的账号体系标识,非多账号体系无需关注此值
*
* @return /
*/
String type() default "";
/**
* 需要校验的角色标识 [ 数组 ]
*
* @return /
*/
String [] value() default {};
/**
* 验证模式:AND | OR,默认AND
* @return 验证模式
*
* @return /
*/
SaMode mode() default SaMode.AND;
/**
* 账号类型
* <p> 建议使用常量,避免因错误拼写带来的bug
* @return see note
*/
String type() default "";
}
@@ -1,3 +1,18 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
@@ -8,24 +23,27 @@ import java.lang.annotation.Target;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 二级认证校验:必须二级认证之后才能进入该方法
* 二级认证校验:客户端必须完成二级认证之后才能进入该方法,否则将被抛出异常。
*
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
* @author kong
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author click33
* @since 1.21.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckSafe {
/**
* 多账号体系下所属的账号体系标识
* @return /
*/
/**
* 多账号体系下所属的账号体系标识,非多账号体系无需关注此值
*
* @return /
*/
String type() default "";
/**
* 要校验的服务
* 要校验的服务
*
* @return /
*/
String value() default SaTokenConsts.DEFAULT_SAFE_AUTH_SERVICE;
@@ -1,3 +1,18 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
@@ -6,12 +21,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 忽略认证:表示被修饰的方法或类无需进行注解认证和路由拦截认证
* 忽略认证:表示被修饰的方法或类无需进行注解认证和路由拦截认证
*
* <h2> 请注意:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效 </h2>
* <h3> 请注意:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效 </h3>
*
* @author kong
* @since: 2022-8-21
* @author click33
* @since 1.31.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@@ -1,9 +1,25 @@
/*
* 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.annotation;
/**
* 注解鉴权的验证模式
* @author kong
* 注解鉴权的验证模式
*
* @author click33
* @since 1.10.0
*/
public enum SaMode {
@@ -1,3 +1,18 @@
/*
* 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 java.util.ArrayList;
@@ -7,11 +22,12 @@ import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.dao.SaTokenDao;
/**
* Application Model,全局作用域的读取值对象
* <p> 在应用全局范围内: 存值、取值
* Application Model,全局作用域的读取值对象
*
* <p> 在应用全局范围内: 存值、取值。数据在应用重启后失效,如果集成了 Redis,则在 Redis 重启后失效。
*
* @author kong
* @since: 2022-8-17
* @author click33
* @since 1.31.0
*/
public class SaApplication implements SaSetValueInterface {
@@ -57,15 +73,15 @@ public class SaApplication implements SaSetValueInterface {
}
/**
* 返回存入的所有 key
* 返回当前存入的所有 key
* @return /
*/
public List<String> keys() {
// 查出来
// 从缓存中查询出所有此前缀的 key
String prefix = splicingDataKey("");
List<String> list = SaManager.getSaTokenDao().searchData(prefix, "", 0, -1, true);
// 裁减掉固定前缀
// 裁减掉固定前缀,保留 key 名称,塞入新集合
int prefixLength = prefix.length();
List<String> list2 = new ArrayList<>();
if(list != null) {
@@ -79,7 +95,7 @@ public class SaApplication implements SaSetValueInterface {
}
/**
* 清空存入的所有 key
* 清空当前存入的所有 key
*/
public void clear() {
List<String> keys = keys();
@@ -89,7 +105,8 @@ public class SaApplication implements SaSetValueInterface {
}
/**
* 拼接key变量存储时使用的key
* 拼接key当存入一个变量时,应该使用的 key
*
* @param key 原始 key
* @return 拼接后的 key 值
*/
@@ -1,12 +1,28 @@
/*
* 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;
/**
* 对取值的一组方法封装
* 对取值的一组方法封装
* <p> 封装 SaStorage、SaSession、SaApplication 等存取值的一些固定方法,减少重复编码 </p>
*
* @author kong
* @since: 2022-8-16
* @author click33
* @since 1.31.0
*/
public interface SaGetValueInterface {
@@ -17,20 +33,20 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public abstract Object get(String key);
Object get(String key);
// --------- 接口提供封装的方法
/**
*
* 取值 (指定默认值)
* 取值 (指定默认值)
*
* @param <T> 默认值的类型
* @param key key
* @param defaultValue 取不到值时返回的默认值
* @return 值
*/
public default <T> T get(String key, T defaultValue) {
default <T> T get(String key, T defaultValue) {
return getValueByDefaultValue(get(key), defaultValue);
}
@@ -39,7 +55,7 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public default String getString(String key) {
default String getString(String key) {
Object value = get(key);
if(value == null) {
return null;
@@ -52,7 +68,7 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public default int getInt(String key) {
default int getInt(String key) {
return getValueByDefaultValue(get(key), 0);
}
@@ -61,7 +77,7 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public default long getLong(String key) {
default long getLong(String key) {
return getValueByDefaultValue(get(key), 0L);
}
@@ -70,7 +86,7 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public default double getDouble(String key) {
default double getDouble(String key) {
return getValueByDefaultValue(get(key), 0.0);
}
@@ -79,7 +95,7 @@ public interface SaGetValueInterface {
* @param key key
* @return 值
*/
public default float getFloat(String key) {
default float getFloat(String key) {
return getValueByDefaultValue(get(key), 0.0f);
}
@@ -90,12 +106,12 @@ public interface SaGetValueInterface {
* @param cs 指定转换类型
* @return 值
*/
public default <T> T getModel(String key, Class<T> cs) {
default <T> T getModel(String key, Class<T> cs) {
return SaFoxUtil.getValueByType(get(key), cs);
}
/**
* 取值 (指定转换类型, 并指定值为Null时返回的默认值)
* 取值 (指定转换类型, 并指定值为 null 时返回的默认值)
* @param <T> 泛型
* @param key key
* @param cs 指定转换类型
@@ -103,7 +119,7 @@ public interface SaGetValueInterface {
* @return 值
*/
@SuppressWarnings("unchecked")
public default <T> T getModel(String key, Class<T> cs, Object defaultValue) {
default <T> T getModel(String key, Class<T> cs, Object defaultValue) {
Object value = get(key);
if(valueIsNull(value)) {
return (T)defaultValue;
@@ -112,11 +128,11 @@ public interface SaGetValueInterface {
}
/**
* 是否含有某个key
* @param key has
* 是否含有某个 key
* @param key 指定 key
* @return 是否含有
*/
public default boolean has(String key) {
default boolean has(String key) {
return !valueIsNull(get(key));
}
@@ -128,7 +144,7 @@ public interface SaGetValueInterface {
* @param value 指定值
* @return 此value是否为null
*/
public default boolean valueIsNull(Object value) {
default boolean valueIsNull(Object value) {
return value == null || value.equals("");
}
@@ -140,14 +156,14 @@ public interface SaGetValueInterface {
* @return 转换后的值
*/
@SuppressWarnings("unchecked")
public default <T> T getValueByDefaultValue(Object value, T defaultValue) {
default <T> T getValueByDefaultValue(Object value, T defaultValue) {
// 如果 obj 为 null,则直接返回默认值
if(valueIsNull(value)) {
return (T)defaultValue;
return defaultValue;
}
// 开始转换
// 开始转换类型
Class<T> cs = (Class<T>) defaultValue.getClass();
return SaFoxUtil.getValueByType(value, cs);
}
@@ -1,12 +1,28 @@
/*
* 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.fun.SaRetFunction;
/**
* 对写值的一组方法封装
* 对写值的一组方法封装
* <p> 封装 SaStorage、SaSession、SaApplication 等存取值的一些固定方法,减少重复编码 </p>
*
* @author kong
* @since: 2022-8-17
* @author click33
* @since 1.31.0
*/
public interface SaSetValueInterface extends SaGetValueInterface {
@@ -18,14 +34,14 @@ public interface SaSetValueInterface extends SaGetValueInterface {
* @param value 值
* @return 对象自身
*/
public abstract SaSetValueInterface set(String key, Object value);
SaSetValueInterface set(String key, Object value);
/**
* 删值
* @param key 要删除的key
* @return 对象自身
*/
public abstract SaSetValueInterface delete(String key);
SaSetValueInterface delete(String key);
// --------- 接口提供封装的方法
@@ -39,7 +55,7 @@ public interface SaSetValueInterface extends SaGetValueInterface {
* @return 值
*/
@SuppressWarnings("unchecked")
public default <T> T get(String key, SaRetFunction fun) {
default <T> T get(String key, SaRetFunction fun) {
Object value = get(key);
if(value == null) {
value = fun.run();
@@ -54,8 +70,8 @@ public interface SaSetValueInterface extends SaGetValueInterface {
* @param value 值
* @return 对象自身
*/
public default SaSetValueInterface setByNull(String key, Object value) {
if(has(key) == false) {
default SaSetValueInterface setByNull(String key, Object value) {
if( ! has(key)) {
set(key, value);
}
return this;
@@ -1,3 +1,18 @@
/*
* 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.basic;
import cn.dev33.satoken.SaManager;
@@ -8,19 +23,20 @@ import cn.dev33.satoken.secure.SaBase64Util;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token Http Basic 认证模块
* @author kong
* Sa-Token Http Basic 认证模块
*
* @author click33
* @since 1.26.0
*/
public class SaBasicTemplate {
/**
* 默认的 Realm 名称
* 默认的 Realm 领域名称
*/
public static final String DEFAULT_REALM = "Sa-Token";
/**
* 设置响应头,并抛出异常
* 在校验失败时,设置响应头,并抛出异常
* @param realm 领域
*/
public void throwNotBasicAuthException(String realm) {
@@ -34,11 +50,11 @@ public class SaBasicTemplate {
*/
public String getAuthorizationValue() {
// 获取请求头 Authorization 参数
// 获取前端提交的请求头 Authorization 参数
String authorization = SaHolder.getRequest().getHeader("Authorization");
// 如果不是以 Basic 作为前缀,则视为无效
if(authorization == null || authorization.startsWith("Basic ") == false) {
if(authorization == null || ! authorization.startsWith("Basic ")) {
return null;
}
@@ -71,7 +87,7 @@ public class SaBasicTemplate {
account = SaManager.getConfig().getBasic();
}
String authorization = getAuthorizationValue();
if(SaFoxUtil.isEmpty(authorization) || authorization.equals(account) == false) {
if(SaFoxUtil.isEmpty(authorization) || ! authorization.equals(account)) {
throwNotBasicAuthException(realm);
}
}
@@ -1,9 +1,25 @@
/*
* 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.basic;
/**
* Sa-Token Http Basic 认证 Util
* @author kong
* Sa-Token Http Basic 认证模块,Util 工具类
*
* @author click33
* @since 1.26.0
*/
public class SaBasicUtil {
@@ -11,7 +27,7 @@ public class SaBasicUtil {
}
/**
* 底层 SaBasicTemplate 对象
* 底层使用的 SaBasicTemplate 对象
*/
public static SaBasicTemplate saBasicTemplate = new SaBasicTemplate();
@@ -1,24 +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.config;
/**
* Sa-Token Cookie写入 相关配置
* @author kong
* Sa-Token Cookie写入 相关配置
*
* @author click33
* @since 1.27.0
*/
public class SaCookieConfig {
/*
Cookie 功能为浏览器通用标准,建议大家自行搜索文章了解各个属性的功能含义,此处源码仅做简单解释。
*/
/**
* 域(写入Cookie时显式指定的作用域, 常用于单点登录二级域名共享Cookie的场景)
* 作用
* <p> 写入 Cookie 时显式指定的作用域, 常用于单点登录二级域名共享 Cookie 的场景。 </p>
* <p> 一般情况下你不需要设置此值,因为浏览器默认会把 Cookie 写到当前域名下。 </p>
*/
private String domain;
/**
* 路径
* 路径 (一般只有当你在一个域名下部署多个项目时才会用到此值。)
*/
private String path;
/**
* 是否只在 https 协议下有效
* 是否只在 https 协议下有效
*/
private Boolean secure = false;
@@ -33,14 +55,20 @@ public class SaCookieConfig {
private String sameSite;
/**
* @return 域 (写入Cookie时显式指定的作用域, 常用于单点登录二级域名共享Cookie的场景)
* 获取:Cookie 作用域
* <p> 写入 Cookie 时显式指定的作用域, 常用于单点登录二级域名共享 Cookie 的场景。 </p>
* <p> 一般情况下你不需要设置此值,因为浏览器默认会把 Cookie 写到当前域名下。 </p>
* @return /
*/
public String getDomain() {
return domain;
}
/**
* @param domain 域 写入Cookie时显式指定的作用域, 常用于单点登录二级域名共享Cookie的场景)
* 写入Cookie 作用域
* <p> 写入 Cookie 时显式指定的作用域, 常用于单点登录二级域名共享 Cookie 的场景。 </p>
* <p> 一般情况下你不需要设置此值,因为浏览器默认会把 Cookie 写到当前域名下。 </p>
* @param domain /
* @return 对象自身
*/
public SaCookieConfig setDomain(String domain) {
@@ -49,14 +77,14 @@ public class SaCookieConfig {
}
/**
* @return 路径
* @return 路径 (一般只有当你在一个域名下部署多个项目时才会用到此值。)
*/
public String getPath() {
return path;
}
/**
* @param path 路径
* @param path 路径 (一般只有当你在一个域名下部署多个项目时才会用到此值。)
* @return 对象自身
*/
public SaCookieConfig setPath(String path) {
@@ -0,0 +1,135 @@
/*
* 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.config;
/**
* Sa-Token API 接口签名/验签 相关配置类
*
* @author click33
* @since 1.34.0
*/
public class SaSignConfig {
/**
* API 调用签名秘钥
*/
private String secretKey;
/**
* 接口调用时的时间戳允许的差距(单位:ms),-1 代表不校验差距,默认15分钟
*
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
* <p> timestamp + nonce 有效防止重放攻击。 </p>
*/
private long timestampDisparity = 1000 * 60 * 15;
/**
* 是否校验 nonce 随机字符串
*/
private Boolean isCheckNonce = true;
/**
* 获取 API 调用签名秘钥
*
* @return /
*/
public String getSecretKey() {
return this.secretKey;
}
/**
* 设置 API 调用签名秘钥
*
* @param secretKey /
* @return 对象自身
*/
public SaSignConfig setSecretKey(String secretKey) {
this.secretKey = secretKey;
return this;
}
/**
* 获取 接口调用时的时间戳允许的差距(单位:ms),-1 代表不校验差距,默认15分钟
*
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
* <p> timestamp + nonce 有效防止重放攻击。 </p>
*
* @return /
*/
public long getTimestampDisparity() {
return this.timestampDisparity;
}
/**
* 设置 接口调用时的时间戳允许的差距(单位:ms),-1 代表不校验差距,默认15分钟
*
* <p> 比如此处你配置了60秒,当一个请求从 client 发起后,如果 server 端60秒内没有处理,60秒后再想处理就无法校验通过了。</p>
* <p> timestamp + nonce 有效防止重放攻击。 </p>
*
* @param timestampDisparity /
* @return 对象自身
*/
public SaSignConfig setTimestampDisparity(long timestampDisparity) {
this.timestampDisparity = timestampDisparity;
return this;
}
/**
* 获取 是否校验 nonce 随机字符串
*
* @return /
*/
public Boolean getIsCheckNonce() {
return this.isCheckNonce;
}
/**
* 设置 是否校验 nonce 随机字符串
*
* @param isCheckNonce /
* @return 对象自身
*/
public SaSignConfig setIsCheckNonce(Boolean isCheckNonce) {
this.isCheckNonce = isCheckNonce;
return this;
}
/**
* 计算保存 nonce 时应该使用的 ttl,单位:秒
* @return /
*/
public long getSaveNonceExpire() {
// 如果 timestampDisparity >= 0,则 nonceTtl 的值等于 timestampDisparity 的值,单位转秒
if(timestampDisparity >= 0) {
return timestampDisparity / 1000;
}
// 否则,nonceTtl 的值为 24 小时
else {
return 60 * 60 * 24;
}
}
@Override
public String toString() {
return "SaSignConfig ["
+ "secretKey=" + secretKey
+ ", timestampDisparity=" + timestampDisparity
+ ", isCheckNonce=" + isCheckNonce
+ "]";
}
}
@@ -1,95 +1,160 @@
/*
* 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.config;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 配置类 Model
* <p>
* 你可以通过yml、properties、java代码等形式配置本类参数,具体请查阅官方文档: https://sa-token.cc/
*
* @author kong
* Sa-Token 配置类 Model
*
* <p>
* 你可以通过yml、properties、java代码等形式配置本类参数,具体请查阅官方文档:
* <a href="https://sa-token.cc">https://sa-token.cc</a>
* </p>
*
* @author click33
* @since 1.10.0
*/
public class SaTokenConfig implements Serializable {
private static final long serialVersionUID = -6541180061782004705L;
/** token名称 (同时也是cookie名称) */
/** token 名称 同时也是 cookie 名称、提交 token 时参数的名称、存储 token 时的 key 前缀) */
private String tokenName = "satoken";
/** token的长久有效期(单位:秒) 默认30天, -1代表永久 */
/** token 有效期单位:秒) 默认30天-1 代表永久有效 */
private long timeout = 60 * 60 * 24 * 30;
/**
* token临时有效期 [指定时间内无操作就视为token过期] (单位: 秒), 默认-1 代表不限制
* (例如可以设置为1800代表30分钟内无操作就过期)
* token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
* 例如可以设置为 1800 代表 30 分钟内无操作就冻结)
*/
private long activityTimeout = -1;
private long activeTimeout = -1;
/** 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) */
/**
* 是否启用动态 activeTimeout 功能,如不需要请设置为 false,节省缓存请求次数
*/
private Boolean dynamicActiveTimeout = false;
/**
* 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
*/
private Boolean isConcurrent = true;
/** 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) */
/**
* 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
*/
private Boolean isShare = true;
/**
* 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有
* 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有意义
*/
private int maxLoginCount = 12;
/** 是否尝试从请求体里读取token */
private Boolean isReadBody = true;
/** 是否尝试从header里读取token */
private Boolean isReadHeader = true;
/** 是否尝试从cookie里读取token */
private Boolean isReadCookie = true;
/** 是否在登录后将 Token 写入到响应头 */
private Boolean isWriteHeader = false;
/** token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) */
private String tokenStyle = "uuid";
/** 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 */
private int dataRefreshPeriod = 30;
/** 获取[token专属session]时是否必须登录 (如果配置为true,会在每次获取[token-session]时校验是否登录) */
private Boolean tokenSessionCheckLogin = true;
/** 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用getLoginId()时进行一次过期检查与续签操作) */
private Boolean autoRenew = true;
/** token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx) */
private String tokenPrefix;
/** 是否在初始化配置时打印版本字符画 */
private Boolean isPrint = true;
/** 是否打印操作日志 */
private Boolean isLog = false;
/** 日志等级(trace、debug、info、warn、error、fatal */
private String logLevel = "trace";
/** 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal */
private int logLevelInt = 1;
/**
* 在每次创建 token 时的最高循环次数,用于保证 token 唯一性(-1=不循环尝试,直接使用)
*/
private int maxTryTimes = 12;
/**
* jwt秘钥 (只有集成 jwt 模块时此参数才会生效)
* 是否尝试从请求体里读取 token
*/
private Boolean isReadBody = true;
/**
* 是否尝试从 header 里读取 token
*/
private Boolean isReadHeader = true;
/**
* 是否尝试从 cookie 里读取 token
*/
private Boolean isReadCookie = true;
/**
* 是否在登录后将 token 写入到响应头
*/
private Boolean isWriteHeader = false;
/**
* token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
*/
private String tokenStyle = "uuid";
/**
* 默认 SaTokenDao 实现类中,每次清理过期数据间隔的时间(单位: 秒),默认值30秒,设置为 -1 代表不启动定时清理
*/
private int dataRefreshPeriod = 30;
/**
* 获取 Token-Session 时是否必须登录(如果配置为true,会在每次获取 getTokenSession() 时校验当前是否登录)
*/
private Boolean tokenSessionCheckLogin = true;
/**
* 是否打开自动续签 activeTimeout (如果此值为 true, 框架会在每次直接或间接调用 getLoginId() 时进行一次过期检查与续签操作)
*/
private Boolean autoRenew = true;
/**
* token 前缀, 前端提交 token 时应该填写的固定前缀,格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
*/
private String tokenPrefix;
/**
* 是否在初始化配置时在控制台打印版本字符画
*/
private Boolean isPrint = true;
/**
* 是否打印操作日志
*/
private Boolean isLog = false;
/**
* 日志等级(trace、debug、info、warn、error、fatal),此值与 logLevelInt 联动
*/
private String logLevel = "trace";
/**
* 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal),此值与 logLevel 联动
*/
private int logLevelInt = 1;
/**
* 是否打印彩色日志
*/
private Boolean isColorLog = null;
/**
* jwt秘钥(只有集成 jwt 相关模块时此参数才会生效)
*/
private String jwtSecretKey;
/**
* Http Basic 认证的账号和密码
* Http Basic 认证的默认账号和密码
*/
private String basic = "";
/** 配置当前项目的网络访问地址 */
/**
* 配置当前项目的网络访问地址
*/
private String currDomain;
/**
@@ -97,25 +162,31 @@ public class SaTokenConfig implements Serializable {
*/
private long sameTokenTimeout = 60 * 60 * 24;
/** 是否校验Same-Token(部分rpc插件有效) */
/**
* 是否校验 Same-Token(部分rpc插件有效)
*/
private Boolean checkSameToken = false;
/**
* Cookie配置对象
*/
public SaCookieConfig cookie = new SaCookieConfig();
/**
* @return token名称 (同时也是cookie名称)
* API 签名配置对象
*/
public SaSignConfig sign = new SaSignConfig();
/**
* @return token 名称 (同时也是: cookie 名称、提交 token 时参数的名称、存储 token 时的 key 前缀)
*/
public String getTokenName() {
return tokenName;
}
/**
* @param tokenName token名称 (同时也是cookie名称)
* @param tokenName token 名称 同时也是 cookie 名称、提交 token 时参数的名称、存储 token 时的 key 前缀)
* @return 对象自身
*/
public SaTokenConfig setTokenName(String tokenName) {
@@ -124,14 +195,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return token的长久有效期(单位:秒) 默认30天, -1代表永久
* @return token 有效期单位:秒) 默认30天-1 代表永久有效
*/
public long getTimeout() {
return timeout;
}
/**
* @param timeout token的长久有效期(单位:秒) 默认30天, -1代表永久
* @param timeout token 有效期单位:秒) 默认30天-1 代表永久有效
* @return 对象自身
*/
public SaTokenConfig setTimeout(long timeout) {
@@ -140,32 +211,48 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return token临时有效期 [指定时间内无操作就视为token过期] (单位: 秒), 默认-1 代表不限制
* (例如可以设置为1800代表30分钟内无操作就过期)
* @return token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
* 例如可以设置为 1800 代表 30 分钟内无操作就冻结)
*/
public long getActivityTimeout() {
return activityTimeout;
public long getActiveTimeout() {
return activeTimeout;
}
/**
* @param activityTimeout token临时有效期 [指定时间内无操作就视为token过期] (单位: 秒), 默认-1 代表不限制
* (例如可以设置为1800代表30分钟内无操作就过期)
* @param activeTimeout token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
* 例如可以设置为 1800 代表 30 分钟内无操作就冻结)
* @return 对象自身
*/
public SaTokenConfig setActivityTimeout(long activityTimeout) {
this.activityTimeout = activityTimeout;
public SaTokenConfig setActiveTimeout(long activeTimeout) {
this.activeTimeout = activeTimeout;
return this;
}
/**
* @return 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
* @return 是否启用动态 activeTimeout 功能,如不需要请设置为 false,节省缓存请求次数
*/
public Boolean getDynamicActiveTimeout() {
return dynamicActiveTimeout;
}
/**
* @param dynamicActiveTimeout 是否启用动态 activeTimeout 功能,如不需要请设置为 false,节省缓存请求次数
* @return 对象自身
*/
public SaTokenConfig setDynamicActiveTimeout(Boolean dynamicActiveTimeout) {
this.dynamicActiveTimeout = dynamicActiveTimeout;
return this;
}
/**
* @return 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
*/
public Boolean getIsConcurrent() {
return isConcurrent;
}
/**
* @param isConcurrent 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
* @param isConcurrent 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录
* @return 对象自身
*/
public SaTokenConfig setIsConcurrent(Boolean isConcurrent) {
@@ -174,14 +261,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
* @return 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个token, 为 false 时每次登录新建一个 token
*/
public Boolean getIsShare() {
return isShare;
}
/**
* @param isShare 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
* @param isShare 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个token, 为 false 时每次登录新建一个 token
* @return 对象自身
*/
public SaTokenConfig setIsShare(Boolean isShare) {
@@ -190,14 +277,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有
* @return 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有意义
*/
public int getMaxLoginCount() {
return maxLoginCount;
}
/**
* @param maxLoginCount 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有
* @param maxLoginCount 同一账号最大登录数量,-1代表不限 (只有在 isConcurrent=true, isShare=false 时此配置才有意义
* @return 对象自身
*/
public SaTokenConfig setMaxLoginCount(int maxLoginCount) {
@@ -206,14 +293,30 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否尝试从请求体里读取token
* @return 在每次创建 token 时的最高循环次数,用于保证 token 唯一性(-1=不循环尝试,直接使用)
*/
public int getMaxTryTimes() {
return maxTryTimes;
}
/**
* @param maxTryTimes 在每次创建 token 时的最高循环次数,用于保证 token 唯一性(-1=不循环尝试,直接使用)
* @return 对象自身
*/
public SaTokenConfig setMaxTryTimes(int maxTryTimes) {
this.maxTryTimes = maxTryTimes;
return this;
}
/**
* @return 是否尝试从请求体里读取 token
*/
public Boolean getIsReadBody() {
return isReadBody;
}
/**
* @param isReadBody 是否尝试从请求体里读取token
* @param isReadBody 是否尝试从请求体里读取 token
* @return 对象自身
*/
public SaTokenConfig setIsReadBody(Boolean isReadBody) {
@@ -222,14 +325,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否尝试从header里读取token
* @return 是否尝试从 header 里读取 token
*/
public Boolean getIsReadHeader() {
return isReadHeader;
}
/**
* @param isReadHeader 是否尝试从header里读取token
* @param isReadHeader 是否尝试从 header 里读取 token
* @return 对象自身
*/
public SaTokenConfig setIsReadHeader(Boolean isReadHeader) {
@@ -238,14 +341,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否尝试从cookie里读取token
* @return 是否尝试从 cookie 里读取 token
*/
public Boolean getIsReadCookie() {
return isReadCookie;
}
/**
* @param isReadCookie 是否尝试从cookie里读取token
* @param isReadCookie 是否尝试从 cookie 里读取 token
* @return 对象自身
*/
public SaTokenConfig setIsReadCookie(Boolean isReadCookie) {
@@ -254,14 +357,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否在登录后将 Token 写入到响应头
* @return 是否在登录后将 token 写入到响应头
*/
public Boolean getIsWriteHeader() {
return isWriteHeader;
}
/**
* @param isWriteHeader 是否在登录后将 Token 写入到响应头
* @param isWriteHeader 是否在登录后将 token 写入到响应头
* @return 对象自身
*/
public SaTokenConfig setIsWriteHeader(Boolean isWriteHeader) {
@@ -270,14 +373,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
* @return token 风格默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
*/
public String getTokenStyle() {
return tokenStyle;
}
/**
* @param tokenStyle token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
* @param tokenStyle token 风格默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik
* @return 对象自身
*/
public SaTokenConfig setTokenStyle(String tokenStyle) {
@@ -286,15 +389,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理
* @return 默认 SaTokenDao 实现类中,每次清理过期数据间隔的时间单位: 秒,默认值30秒,设置为 -1 代表不启动定时清理
*/
public int getDataRefreshPeriod() {
return dataRefreshPeriod;
}
/**
* @param dataRefreshPeriod 默认dao实现类中,每次清理过期数据间隔的时间 (单位: 秒)
* ,默认值30秒,设置为-1代表不启动定时清理
* @param dataRefreshPeriod 默认 SaTokenDao 实现类中,每次清理过期数据间隔的时间单位: 秒),默认值30秒,设置为 -1 代表不启动定时清理
* @return 对象自身
*/
public SaTokenConfig setDataRefreshPeriod(int dataRefreshPeriod) {
@@ -303,15 +405,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 获取[token专属session]时是否必须登录 (如果配置为true,会在每次获取[token-session]时校验是否登录)
* @return 获取 Token-Session 时是否必须登录如果配置为true,会在每次获取 getTokenSession() 时校验当前是否登录
*/
public Boolean getTokenSessionCheckLogin() {
return tokenSessionCheckLogin;
}
/**
* @param tokenSessionCheckLogin 获取[token专属session]时是否必须登录
* (如果配置为true,会在每次获取[token-session]时校验是否登录)
* @param tokenSessionCheckLogin 获取 Token-Session 时是否必须登录(如果配置为true,会在每次获取 getTokenSession() 时校验当前是否登录)
* @return 对象自身
*/
public SaTokenConfig setTokenSessionCheckLogin(Boolean tokenSessionCheckLogin) {
@@ -320,14 +421,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用getLoginId()时进行一次过期检查与续签操作)
* @return 是否打开自动续签 activeTimeout 如果此值为 true, 框架会在每次直接或间接调用 getLoginId() 时进行一次过期检查与续签操作
*/
public Boolean getAutoRenew() {
return autoRenew;
}
/**
* @param autoRenew 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用getLoginId()时进行一次过期检查与续签操作)
* @param autoRenew 是否打开自动续签 activeTimeout 如果此值为 true, 框架会在每次直接或间接调用 getLoginId() 时进行一次过期检查与续签操作
* @return 对象自身
*/
public SaTokenConfig setAutoRenew(Boolean autoRenew) {
@@ -336,14 +437,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
* @return token 前缀, 前端提交 token 时应该填写的固定前缀,格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
*/
public String getTokenPrefix() {
return tokenPrefix;
}
/**
* @param tokenPrefix token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
* @param tokenPrefix token 前缀, 前端提交 token 时应该填写的固定前缀,格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
* @return 对象自身
*/
public SaTokenConfig setTokenPrefix(String tokenPrefix) {
@@ -352,14 +453,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 是否在初始化配置时打印版本字符画
* @return 是否在初始化配置时在控制台打印版本字符画
*/
public Boolean getIsPrint() {
return isPrint;
}
/**
* @param isPrint 是否在初始化配置时打印版本字符画
* @param isPrint 是否在初始化配置时在控制台打印版本字符画
* @return 对象自身
*/
public SaTokenConfig setIsPrint(Boolean isPrint) {
@@ -384,14 +485,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 日志等级(trace、debug、info、warn、error、fatal
* @return 日志等级(trace、debug、info、warn、error、fatal,此值与 logLevelInt 联动
*/
public String getLogLevel() {
return logLevel;
}
/**
* @param logLevel 日志等级(trace、debug、info、warn、error、fatal
* @param logLevel 日志等级(trace、debug、info、warn、error、fatal,此值与 logLevelInt 联动
* @return 对象自身
*/
public SaTokenConfig setLogLevel(String logLevel) {
@@ -401,31 +502,51 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal
* @return 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal,此值与 logLevel 联动
*/
public int getLogLevelInt() {
return logLevelInt;
}
/**
* @param logLevelInt 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal
* @param logLevelInt 日志等级 int 值(1=trace、2=debug、3=info、4=warn、5=error、6=fatal,此值与 logLevel 联动
* @return 对象自身
*/
public SaTokenConfig setLogLeveInt(int logLevelInt) {
public SaTokenConfig setLogLevelInt(int logLevelInt) {
this.logLevelInt = logLevelInt;
this.logLevel = SaFoxUtil.translateLogLevelToString(logLevelInt);
return this;
}
/**
* @return jwt秘钥 (只有集成 jwt 模块时此参数才会生效)
* 获取:是否打印彩色日志
*
* @return isColorLog 是否打印彩色日志
*/
public Boolean getIsColorLog() {
return this.isColorLog;
}
/**
* 设置:是否打印彩色日志
*
* @param isColorLog 是否打印彩色日志
* @return 对象自身
*/
public SaTokenConfig setIsColorLog(Boolean isColorLog) {
this.isColorLog = isColorLog;
return this;
}
/**
* @return jwt秘钥(只有集成 jwt 相关模块时此参数才会生效)
*/
public String getJwtSecretKey() {
return jwtSecretKey;
}
/**
* @param jwtSecretKey jwt秘钥 (只有集成 jwt 模块时此参数才会生效)
* @param jwtSecretKey jwt秘钥只有集成 jwt 相关模块时此参数才会生效
* @return 对象自身
*/
public SaTokenConfig setJwtSecretKey(String jwtSecretKey) {
@@ -434,14 +555,14 @@ public class SaTokenConfig implements Serializable {
}
/**
* @return Http Basic 认证的账号和密码
* @return Http Basic 认证的默认账号和密码
*/
public String getBasic() {
return basic;
}
/**
* @param basic Http Basic 认证的账号和密码
* @param basic Http Basic 认证的默认账号和密码
* @return 对象自身
*/
public SaTokenConfig setBasic(String basic) {
@@ -512,16 +633,34 @@ public class SaTokenConfig implements Serializable {
this.cookie = cookie;
return this;
}
/**
* @return API 签名全局配置对象
*/
public SaSignConfig getSign() {
return sign;
}
/**
* @param sign API 签名全局配置对象
* @return 对象自身
*/
public SaTokenConfig setSign(SaSignConfig sign) {
this.sign = sign;
return this;
}
@Override
public String toString() {
return "SaTokenConfig ["
+ "tokenName=" + tokenName
+ ", timeout=" + timeout
+ ", activityTimeout=" + activityTimeout
+ ", activeTimeout=" + activeTimeout
+ ", dynamicActiveTimeout=" + dynamicActiveTimeout
+ ", isConcurrent=" + isConcurrent
+ ", isShare=" + isShare
+ ", maxLoginCount=" + maxLoginCount
+ ", maxLoginCount=" + maxLoginCount
+ ", maxTryTimes=" + maxTryTimes
+ ", isReadBody=" + isReadBody
+ ", isReadHeader=" + isReadHeader
+ ", isReadCookie=" + isReadCookie
@@ -535,74 +674,40 @@ public class SaTokenConfig implements Serializable {
+ ", isLog=" + isLog
+ ", logLevel=" + logLevel
+ ", logLevelInt=" + logLevelInt
+ ", isColorLog=" + isColorLog
+ ", jwtSecretKey=" + jwtSecretKey
+ ", basic=" + basic
+ ", currDomain=" + currDomain
+ ", sameTokenTimeout=" + sameTokenTimeout
+ ", checkSameToken=" + checkSameToken
+ ", cookie=" + cookie
+ ", cookie=" + cookie
+ ", sign=" + sign
+ "]";
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 getIsReadHeader() ,使用方式保持不变 </h1>
* @return 是否尝试从header里读取token
* 请更改为 getActiveTimeout()
* @return token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
* (例如可以设置为 1800 代表 30 分钟内无操作就冻结)
*/
@Deprecated
public Boolean getIsReadHead() {
return isReadHeader;
public long getActivityTimeout() {
System.err.println("配置项已过期,请更换:sa-token.activity-timeout -> sa-token.active-timeout");
return activeTimeout;
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 setIsReadHeader() ,使用方式保持不变 </h1>
* @param isReadHead 是否尝试从header里读取token
* 请更改为 setActiveTimeout()
* @param activityTimeout token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
* (例如可以设置为 1800 代表 30 分钟内无操作就冻结)
* @return 对象自身
*/
@Deprecated
public SaTokenConfig setIsReadHead(Boolean isReadHead) {
this.isReadHeader = isReadHead;
public SaTokenConfig setActivityTimeout(long activityTimeout) {
System.err.println("配置项已过期,请更换:sa-token.activity-timeout -> sa-token.active-timeout");
this.activeTimeout = activityTimeout;
return this;
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 getSameTokenTimeout() ,使用方式保持不变 </h1>
* @return Id-Token的有效期 (单位: 秒)
*/
@Deprecated
public long getIdTokenTimeout() {
return sameTokenTimeout;
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 setSameTokenTimeout() ,使用方式保持不变 </h1>
* @param idTokenTimeout Id-Token的有效期 (单位: 秒)
* @return 对象自身
*/
@Deprecated
public SaTokenConfig setIdTokenTimeout(long idTokenTimeout) {
this.sameTokenTimeout = idTokenTimeout;
return this;
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 getCheckSameToken() ,使用方式保持不变 </h1>
* @return 是否校验Id-Token(部分rpc插件有效)
*/
@Deprecated
public Boolean getCheckIdToken() {
return checkSameToken;
}
/**
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 setCheckSameToken() ,使用方式保持不变 </h1>
* @param checkIdToken 是否校验Id-Token(部分rpc插件有效)
* @return 对象自身
*/
@Deprecated
public SaTokenConfig setCheckIdToken(Boolean checkIdToken) {
this.checkSameToken = checkIdToken;
return this;
}
}
@@ -1,3 +1,18 @@
/*
* 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.config;
import java.io.IOException;
@@ -13,11 +28,11 @@ import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token配置文件的构建工厂类
* <p>
* 用于手动读取配置文件初始化 SaTokenConfig 对象,只有在非IOC环境下你才会用到此类
*
* <p> 用于手动读取配置文件初始化 SaTokenConfig 对象,只有在非IOC环境下你才会用到此类 </p>
*
* @author kong
* @since 2022-10-30
* @author click33
* @since 1.10.0
*/
public class SaTokenConfigFactory {
@@ -30,7 +45,7 @@ public class SaTokenConfigFactory {
public static String configPath = "sa-token.properties";
/**
* 根据configPath路径获取配置信息
* 根据 configPath 路径获取配置信息
*
* @return 一个SaTokenConfig对象
*/
@@ -42,13 +57,13 @@ public class SaTokenConfigFactory {
* 根据指定路径路径获取配置信息
*
* @param path 配置文件路径
* @return 一个SaTokenConfig对象
* @return 一个 SaTokenConfig 对象
*/
public static SaTokenConfig createConfig(String path) {
Map<String, String> map = readPropToMap(path);
if (map == null) {
// if (map == null) {
// throw new RuntimeException("找不到配置文件:" + configPath, null);
}
// }
return (SaTokenConfig) initPropByMap(map, new SaTokenConfig());
}
@@ -59,7 +74,7 @@ public class SaTokenConfigFactory {
* @return 一个Map
*/
private static Map<String, String> readPropToMap(String propertiesPath) {
Map<String, String> map = new HashMap<String, String>(16);
Map<String, String> map = new HashMap<>(16);
try {
InputStream is = SaTokenConfigFactory.class.getClassLoader().getResourceAsStream(propertiesPath);
if (is == null) {
@@ -86,11 +101,11 @@ public class SaTokenConfigFactory {
private static Object initPropByMap(Map<String, String> map, Object obj) {
if (map == null) {
map = new HashMap<String, String>(16);
map = new HashMap<>(16);
}
// 1、取出类型
Class<?> cs = null;
Class<?> cs;
if (obj instanceof Class) {
// 如果是一个类型,则将obj=null,以便完成静态属性反射赋值
cs = (Class<?>) obj;
@@ -1,3 +1,18 @@
/*
* 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.context;
import cn.dev33.satoken.SaManager;
@@ -7,52 +22,58 @@ import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
/**
* Sa-Token 上下文持有类
* @author kong
* Sa-Token 上下文持有类,你可以通过此类快速获取当前环境下的 SaRequest、SaResponse、SaStorage、SaApplication 对象。
*
* @author click33
* @since 1.18.0
*/
public class SaHolder {
/**
* 获取当前请求的 SaTokenContext
* 获取当前请求的 SaTokenContext 上下文对象
* @see SaTokenContext
*
* @return see note
* @return /
*/
public static SaTokenContext getContext() {
return SaManager.getSaTokenContextOrSecond();
}
/**
* 获取当前请求的 [Request] 对象
* 获取当前请求的 Request 包装对象
* @see SaRequest
*
* @return see note
* @return /
*/
public static SaRequest getRequest() {
return SaManager.getSaTokenContextOrSecond().getRequest();
}
/**
* 获取当前请求的 [Response] 对象
* 获取当前请求的 Response 包装对象
* @see SaResponse
*
* @return see note
* @return /
*/
public static SaResponse getResponse() {
return SaManager.getSaTokenContextOrSecond().getResponse();
}
/**
* 获取当前请求的 [存储器] 对象
*
* @return see note
* 获取当前请求的 Storage 包装对象
* @see SaStorage
*
* @return /
*/
public static SaStorage getStorage() {
return SaManager.getSaTokenContextOrSecond().getStorage();
}
/**
* 获取全局 SaApplication 对象
* 获取全局 SaApplication 对象
* @see SaApplication
*
* @return see note
* @return /
*/
public static SaApplication getApplication() {
return SaApplication.defaultInstance;
@@ -1,3 +1,18 @@
/*
* 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.context;
import cn.dev33.satoken.context.model.SaRequest;
@@ -6,46 +21,59 @@ import cn.dev33.satoken.context.model.SaResponse;
/**
* Sa-Token 上下文处理器
* @author kong
*
* <p> 上下文处理器封装了当前应用环境的底层操作,是 Sa-Token 对接不同 web 框架的关键,详细可参考在线文档 “自定义 SaTokenContext 指南”章节 </p>
*
* @author click33
* @since 1.16.0
*/
public interface SaTokenContext {
/**
* 获取当前请求的 [Request] 对象
* 获取当前请求的 Request 包装对象
* @see SaRequest
*
* @return see note
* @return /
*/
public SaRequest getRequest();
SaRequest getRequest();
/**
* 获取当前请求的 [Response] 对象
* 获取当前请求的 Response 包装对象
* @see SaResponse
*
* @return see note
* @return /
*/
public SaResponse getResponse();
SaResponse getResponse();
/**
* 获取当前请求的 [存储器] 对象
* 获取当前请求的 Storage 包装对象
* @see SaStorage
*
* @return see note
* @return /
*/
public SaStorage getStorage();
SaStorage getStorage();
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
* 判断:指定路由匹配符是否可以匹配成功指定路径
* <pre>
* 判断规则由底层 web 框架决定,例如在 springboot 中:
* - matchPath("/user/*", "/user/login") 返回: true
* - matchPath("/user/*", "/article/edit") 返回: false
* </pre>
*
* @param pattern 路由匹配符
* @param path 需要匹配的路径
* @return see note
* @return /
*/
public boolean matchPath(String pattern, String path);
boolean matchPath(String pattern, String path);
/**
* 此上下文是否有效
* 判断:在本次请求中,此上下文是否可用。
* <p> 例如在部分 rpc 调用时, 一级上下文会返回 false,这时候框架就会选择使用二级上下文来处理请求 </p>
*
* @return /
*/
public default boolean isValid() {
default boolean isValid() {
return false;
}
@@ -1,3 +1,18 @@
/*
* 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.context;
import cn.dev33.satoken.context.model.SaRequest;
@@ -7,15 +22,15 @@ import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.InvalidContextException;
/**
* Sa-Token 上下文处理器 [默认实现类]
* Sa-Token 上下文处理器 [ 默认实现类 ]
*
* <p>
* 一般情况下框架会为你自动注入合适的上下文处理器,如果代码断点走到了此默认实现类,
* 说明你引入的依赖有问题或者错误的调用了Sa-Token的API, 请在[在线开发文档 → 附录 → 常见问题排查] 中按照提示进行排查
* 一般情况下框架会为你自动注入合适的上下文处理器,如果代码断点走到了此默认实现类,
* 说明你引入的依赖有问题或者错误的调用了 Sa-Token 的API 请在 [ 在线开发文档 → 附录 → 常见问题排查 ] 中按照提示进行排查
* </p>
*
* @author kong
*
* @author click33
* @since 1.16.0
*/
public class SaTokenContextDefaultImpl implements SaTokenContext {
@@ -25,37 +40,25 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
public static SaTokenContextDefaultImpl defaultContext = new SaTokenContextDefaultImpl();
/**
* 默认的错误提示语
* 错误提示语
*/
public static final String ERROR_MESSAGE = "未能获取有效的上下文处理器";
/**
* 获取当前请求的 [Request] 对象
*/
@Override
public SaRequest getRequest() {
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
/**
* 获取当前请求的 [Response] 对象
*/
@Override
public SaResponse getResponse() {
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
/**
* 获取当前请求的 [存储器] 对象
*/
@Override
public SaStorage getStorage() {
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*/
@Override
public boolean matchPath(String pattern, String path) {
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
@@ -1,3 +1,18 @@
/*
* 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.context;
import cn.dev33.satoken.context.model.SaRequest;
@@ -5,15 +20,17 @@ import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
/**
* Sa-Token 上下文处理器 [ThreadLocal版本]
* Sa-Token 上下文处理器 [ ThreadLocal 版本 ]
*
* <p>
* 使用 [ThreadLocal版本] 上下文处理器需要在全局过滤器或者拦截器内率先调用
* SaTokenContextForThreadLocalStorage.setBox(req,res, sto) 初始化上下文
* 使用 [ ThreadLocal 版本 ] 上下文处理器需要在全局过滤器或者拦截器内率先调用
* SaTokenContextForThreadLocalStorage.setBox(req, res, sto) 初始化上下文
* </p>
*
* @author kong
*
* <p> 一般情况下你不需要直接操作此类,因为框架的 starter 集成包里已经封装了完整的上下文操作 </p>
*
* @author click33
* @since 1.16.0
*/
public class SaTokenContextForThreadLocal implements SaTokenContext {
@@ -1,3 +1,18 @@
/*
* 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.context;
import cn.dev33.satoken.context.model.SaRequest;
@@ -7,20 +22,22 @@ import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.InvalidContextException;
/**
* Sa-Token 上下文处理器 [ThreadLocal版本] ---- 对象存储器
*
* @author kong
* Sa-Token 上下文处理器 [ThreadLocal 版本] ---- 对象存储器
*
* <p> 一般情况下你不需要直接操作此类,因为框架的 starter 集成包里已经封装了完整的上下文操作 </p>
*
* @author click33
* @since 1.16.0
*/
public class SaTokenContextForThreadLocalStorage {
/**
* 基于 ThreadLocal 的 [Box存储器]
* 基于 ThreadLocal 的 [ Box 存储器 ]
*/
public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<Box>();
public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<>();
/**
* 初始化 [Box存储器]
* 初始化当前线程的 [ Box 存储器 ]
* @param request {@link SaRequest}
* @param response {@link SaResponse}
* @param storage {@link SaStorage}
@@ -28,26 +45,26 @@ public class SaTokenContextForThreadLocalStorage {
public static void setBox(SaRequest request, SaResponse response, SaStorage storage) {
Box bok = new Box(request, response, storage);
boxThreadLocal.set(bok);
};
}
/**
* 清除 [Box存储器]
* 清除当前线程的 [ Box 存储器 ]
*/
public static void clearBox() {
boxThreadLocal.remove();
};
}
/**
* 获取 [Box存储器]
* @return see note
* 获取当前线程的 [ Box 存储器 ]
* @return /
*/
public static Box getBox() {
return boxThreadLocal.get();
};
}
/**
* 获取 [Box存储器], 如果为空则抛出异常
* @return see note
* 获取当前线程的 [ Box 存储器 ], 如果为空则抛出异常
* @return /
*/
public static Box getBoxNotNull() {
Box box = boxThreadLocal.get();
@@ -55,30 +72,30 @@ public class SaTokenContextForThreadLocalStorage {
throw new InvalidContextException("未能获取有效的上下文").setCode(SaErrorCode.CODE_10002);
}
return box;
};
}
/**
* 在 [Box存储器] 获取 [Request] 对象
* 在当前线程的 SaRequest 包装对象
*
* @return see note
* @return /
*/
public static SaRequest getRequest() {
return getBoxNotNull().getRequest();
}
/**
* 在 [Box存储器] 获取 [Response] 对象
* 在当前线程的 SaResponse 包装对象
*
* @return see note
* @return /
*/
public static SaResponse getResponse() {
return getBoxNotNull().getResponse();
}
/**
* 在 [Box存储器] 获取 [存储器] 对象
* 在当前线程的 SaStorage 存储器包装对象
*
* @return see note
* @return /
*/
public static SaStorage getStorage() {
return getBoxNotNull().getStorage();
@@ -86,12 +103,10 @@ public class SaTokenContextForThreadLocalStorage {
/**
* 临时内部类,用于存储[request、response、storage]三个对象
* @author kong
*/
/**
* @author kong
* Box 临时内部类,用于存储 [ SaRequest、SaResponse、SaStorage ] 三个包装对象
*
* @author click33
* @since 1.16.0
*/
public static class Box {
@@ -1,3 +1,18 @@
/*
* 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.context.model;
import java.time.Instant;
@@ -10,9 +25,10 @@ import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Cookie Model
* @author kong
* Cookie Model,代表一个 Cookie 应该具有的所有参数
*
* @author click33
* @since 1.16.0
*/
public class SaCookie {
@@ -32,7 +48,7 @@ public class SaCookie {
private String value;
/**
* 有效时长 (单位:秒),-1代表为临时Cookie 浏览器关闭后自动删除
* 有效时长 (单位:秒),-1 代表为临时Cookie 浏览器关闭后自动删除
*/
private int maxAge = -1;
@@ -113,14 +129,14 @@ public class SaCookie {
}
/**
* @return 有效时长 (单位:秒),-1代表为临时Cookie 浏览器关闭后自动删除
* @return 有效时长 (单位:秒),-1 代表为临时Cookie 浏览器关闭后自动删除
*/
public int getMaxAge() {
return maxAge;
}
/**
* @param maxAge 有效时长 (单位:秒),-1代表为临时Cookie 浏览器关闭后自动删除
* @param maxAge 有效时长 (单位:秒),-1 代表为临时Cookie 浏览器关闭后自动删除
* @return 对象自身
*/
public SaCookie setMaxAge(int maxAge) {
@@ -220,7 +236,7 @@ public class SaCookie {
/**
* 构建一下
*/
public void builde() {
public void builder() {
if(path == null) {
path = "/";
}
@@ -231,7 +247,7 @@ public class SaCookie {
* @return /
*/
public String toHeaderValue() {
this.builde();
this.builder();
if(SaFoxUtil.isEmpty(name)) {
throw new SaTokenException("name不能为空").setCode(SaErrorCode.CODE_12002);
@@ -1,36 +1,55 @@
/*
* 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.context.model;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.List;
import java.util.Map;
/**
* Request 包装类
* @author kong
* Request 请求对象 包装类
*
* @author click33
* @since 1.16.0
*/
public interface SaRequest {
/**
* 获取底层源对象
* @return see note
* 获取底层被包装的源对象
* @return /
*/
public Object getSource();
Object getSource();
/**
* 在 [请求体] 里获取一个值
* 在 [ 请求体 ] 里获取一个参数
* @param name 键
* @return 值
*/
public String getParam(String name);
String getParam(String name);
/**
* 在 [请求体] 里获取一个值,值为空时返回默认值
* 在 [ 请求体 ] 里获取一个参数值,值为空时返回默认值
* @param name 键
* @param defaultValue 值为空时的默认值
* @return 值
*/
public default String getParam(String name, String defaultValue) {
default String getParam(String name, String defaultValue) {
String value = getParam(name);
if(SaFoxUtil.isEmpty(value)) {
return defaultValue;
@@ -39,53 +58,64 @@ public interface SaRequest {
}
/**
* 检测提供的参数是否为指定值
* 在 [ 请求体 ] 里检测提供的参数是否为指定值
* @param name 键
* @param value 值
* @return 是否相等
*/
public default boolean isParam(String name, String value) {
default boolean isParam(String name, String value) {
String paramValue = getParam(name);
return SaFoxUtil.isNotEmpty(paramValue) && paramValue.equals(value);
}
/**
* 检测请求是否提供了指定参数
* 在 [ 请求体 ] 里检测请求是否提供了指定参数
* @param name 参数名称
* @return 是否提供
*/
public default boolean hasParam(String name) {
default boolean hasParam(String name) {
return SaFoxUtil.isNotEmpty(getParam(name));
}
/**
* 在 [请求体] 里获取一个值 (此值必须存在,否则抛出异常 )
* 在 [ 请求体 ] 里获取一个值 (此值必须存在,否则抛出异常 )
* @param name 键
* @return 参数值
*/
public default String getParamNotNull(String name) {
default String getParamNotNull(String name) {
String paramValue = getParam(name);
if(SaFoxUtil.isEmpty(paramValue)) {
throw new SaTokenException("缺少参数:" + name).setCode(SaErrorCode.CODE_12001);
}
return paramValue;
}
/**
* [请求] 里获取一个值
* 获取 [ 请求] 里提交的所有参数名称
* @return 参数名称列表
*/
List<String> getParamNames();
/**
* 获取 [ 请求体 ] 里提交的所有参数
* @return 参数列表
*/
Map<String, String> getParamMap();
/**
* 在 [ 请求头 ] 里获取一个值
* @param name 键
* @return 值
*/
public String getHeader(String name);
String getHeader(String name);
/**
* 在 [请求头] 里获取一个值
* 在 [ 请求头 ] 里获取一个值
* @param name 键
* @param defaultValue 值为空时的默认值
* @return 值
*/
public default String getHeader(String name, String defaultValue) {
default String getHeader(String name, String defaultValue) {
String value = getHeader(name);
if(SaFoxUtil.isEmpty(value)) {
return defaultValue;
@@ -94,44 +124,44 @@ public interface SaRequest {
}
/**
* 在 [Cookie作用域] 里获取一个值
* 在 [ Cookie作用域 ] 里获取一个值
* @param name 键
* @return 值
*/
public String getCookieValue(String name);
String getCookieValue(String name);
/**
* 返回当前请求path (不包括上下文名称)
* @return see note
* @return /
*/
public String getRequestPath();
String getRequestPath();
/**
* 返回当前请求path是否为指定值
* 返回当前请求 path 是否为指定值
* @param path path
* @return see note
* @return /
*/
public default boolean isPath(String path) {
default boolean isPath(String path) {
return getRequestPath().equals(path);
}
/**
* 返回当前请求的url,不带query参数,例:http://xxx.com/test
* @return see note
* @return /
*/
public String getUrl();
String getUrl();
/**
* 返回当前请求的类型
* @return see note
* @return /
*/
public String getMethod();
String getMethod();
/**
* 此请求是否为Ajax请求
* @return see note
* 判断此请求是否为 Ajax 异步请求
* @return /
*/
public default boolean isAjax() {
default boolean isAjax() {
return getHeader("X-Requested-With") != null;
}
@@ -140,6 +170,6 @@ public interface SaRequest {
* @param path 转发地址
* @return 任意值
*/
public Object forward(String path);
Object forward(String path);
}
@@ -1,28 +1,44 @@
/*
* 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.context.model;
/**
* Response 包装类
* @author kong
* Response 响应对象 包装类
*
* @author click33
* @since 1.16.0
*/
public interface SaResponse {
/**
* 指定前端可以获取到哪些响应头时使用的参数名
*/
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
/**
* 获取底层源对象
* @return see note
* 获取底层被包装的源对象
* @return /
*/
public Object getSource();
Object getSource();
/**
* 删除指定Cookie
* @param name Cookie名称
*/
public default void deleteCookie(String name) {
default void deleteCookie(String name) {
addCookie(name, null, null, null, 0);
}
@@ -32,7 +48,7 @@ public interface SaResponse {
* @param path Cookie 路径
* @param domain Cookie 作用域
*/
public default void deleteCookie(String name, String path, String domain) {
default void deleteCookie(String name, String path, String domain) {
addCookie(name, null, path, domain, 0);
}
@@ -44,7 +60,7 @@ public interface SaResponse {
* @param domain Cookie的作用域
* @param timeout 过期时间 (秒)
*/
public default void addCookie(String name, String value, String path, String domain, int timeout) {
default void addCookie(String name, String value, String path, String domain, int timeout) {
this.addCookie(new SaCookie(name, value).setPath(path).setDomain(domain).setMaxAge(timeout));
}
@@ -52,7 +68,7 @@ public interface SaResponse {
* 写入指定Cookie
* @param cookie Cookie-Model
*/
public default void addCookie(SaCookie cookie) {
default void addCookie(SaCookie cookie) {
this.addHeader(SaCookie.HEADER_NAME, cookie.toHeaderValue());
}
@@ -61,7 +77,7 @@ public interface SaResponse {
* @param sc 响应状态码
* @return 对象自身
*/
public SaResponse setStatus(int sc);
SaResponse setStatus(int sc);
/**
* 在响应头里写入一个值
@@ -69,7 +85,7 @@ public interface SaResponse {
* @param value 值
* @return 对象自身
*/
public SaResponse setHeader(String name, String value);
SaResponse setHeader(String name, String value);
/**
* 在响应头里添加一个值
@@ -77,14 +93,14 @@ public interface SaResponse {
* @param value 值
* @return 对象自身
*/
public SaResponse addHeader(String name, String value);
SaResponse addHeader(String name, String value);
/**
* 在响应头写入 [Server] 服务器名称
* @param value 服务器名称
* @return 对象自身
*/
public default SaResponse setServer(String value) {
default SaResponse setServer(String value) {
return this.setHeader("Server", value);
}
@@ -93,6 +109,6 @@ public interface SaResponse {
* @param url 重定向地址
* @return 任意值
*/
public Object redirect(String url);
Object redirect(String url);
}
@@ -1,34 +1,50 @@
/*
* 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.context.model;
import cn.dev33.satoken.application.SaSetValueInterface;
/**
* Storage Model,请求作用域的读取值对象
* <p> 在一次请求范围内: 存值、取值
*
* @author kong
* Storage Model,请求作用域的读取值对象
*
* <p> 在一次请求范围内: 存值、取值。数据在请求结束后失效。
*
* @author click33
* @since 1.16.0
*/
public interface SaStorage extends SaSetValueInterface {
/**
* 获取底层源对象
* @return see note
* 获取底层被包装的源对象
* @return /
*/
public Object getSource();
Object getSource();
// ---- 实现接口存取值方法
/** 取值 */
@Override
public Object get(String key);
Object get(String key);
/** 写值 */
@Override
public SaStorage set(String key, Object value);
SaStorage set(String key, Object value);
/** 删值 */
@Override
public SaStorage delete(String key);
SaStorage delete(String key);
}
@@ -1,4 +1,20 @@
/*
* 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.
*/
/**
* 因为不能确定最终运行的容器属于标准Servlet模型还是非Servlet模型,特封装此包下的包装类进行对接
* 因为不能确定最终运行的 web 容器属于标准 Servlet 模型还是非 Servlet 模型,特封装此包下的包装类进行对接
* 调用路径为:Sa-Token 功能函数 -> SaRequest 封装接口 -> SaRequest 具体实现类。
*/
package cn.dev33.satoken.context.model;
@@ -1,3 +1,18 @@
/*
* 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.context.second;
import cn.dev33.satoken.context.SaTokenContext;
@@ -5,10 +20,12 @@ import cn.dev33.satoken.context.SaTokenContext;
/**
* Sa-Token 二级Context - 基础接口
*
* <p> (利用继承机制实现区别 [一级Context] 与 [二级Context] 的目的)
*
* @author kong
* <p> (利用继承机制实现区别 [ 一级Context ] 与 [ 二级Context ] 的目的)
*
* @see SaTokenContext SaTokenContext 上下文处理器
*
* @author click33
* @since 1.28.0
*/
public interface SaTokenSecondContext extends SaTokenContext {
@@ -1,18 +1,33 @@
/*
* 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.context.second;
/**
* Sa-Token 二级Context - 创建器
*
* @author kong
*
* @author click33
* @since 1.28.0
*/
@FunctionalInterface
public interface SaTokenSecondContextCreator {
/**
* 创建一个二级 Context
* 创建一个二级 Context 处理器
* @return /
*/
public SaTokenSecondContext create();
SaTokenSecondContext create();
}
@@ -1,163 +1,187 @@
/*
* 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.dao;
import java.util.List;
import cn.dev33.satoken.session.SaSession;
import java.util.List;
/**
* Sa-Token持久层接口
* @author kong
* Sa-Token 持久层接口
*
* <p>
* 此接口的不同实现类可将数据存储至不同位置,如:内存Map、Redis 等等。
* 如果你要自定义数据存储策略,也需通过实现此接口来完成。
* </p>
*
* @author click33
* @since 1.10.0
*/
public interface SaTokenDao {
/** 常量,表示一个key永不过期 (在一个key被标注为永远不过期时返回此值) */
public static final long NEVER_EXPIRE = -1;
/** 常量,表示一个 key 永不过期 在一个 key 被标注为永远不过期时返回此值 */
long NEVER_EXPIRE = -1;
/** 常量,表示系统中不存在这个缓存 (在对不存在的key获取剩余存活时间时返回此值) */
public static final long NOT_VALUE_EXPIRE = -2;
/** 常量,表示系统中不存在这个缓存在对不存在的 key 获取剩余存活时间时返回此值 */
long NOT_VALUE_EXPIRE = -2;
// --------------------- 字符串读写 ---------------------
/**
* 获取Value,如无返空
* 获取 value,如无返空
*
* @param key 键名称
* @return value
*/
public String get(String key);
String get(String key);
/**
* 写入Value,并设定存活时间 (单位: 秒)
* 写入 value,并设定存活时间单位: 秒
*
* @param key 键名称
* @param value 值
* @param timeout 过期时间(值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储)
* @param timeout 数据有效期(值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储
*/
public void set(String key, String value, long timeout);
void set(String key, String value, long timeout);
/**
* 更新Value (过期时间不变)
* 更新 value 过期时间不变
* @param key 键名称
* @param value 值
*/
public void update(String key, String value);
void update(String key, String value);
/**
* 删除Value
* 删除 value
* @param key 键名称
*/
public void delete(String key);
void delete(String key);
/**
* 获取Value的剩余存活时间 (单位: 秒)
* @param key 指定key
* @return 这个key的剩余存活时间
* 获取 value 的剩余存活时间单位: 秒
* @param key 指定 key
* @return 这个 key 的剩余存活时间
*/
public long getTimeout(String key);
long getTimeout(String key);
/**
* 修改Value的剩余存活时间 (单位: 秒)
* @param key 指定key
* @param timeout 过期时间
* 修改 value 的剩余存活时间单位: 秒
* @param key 指定 key
* @param timeout 过期时间(单位: 秒)
*/
public void updateTimeout(String key, long timeout);
void updateTimeout(String key, long timeout);
// --------------------- 对象读写 ---------------------
/**
* 获取Object,如无返空
* 获取 Object,如无返空
* @param key 键名称
* @return object
*/
public Object getObject(String key);
Object getObject(String key);
/**
* 写入Object,并设定存活时间 (单位: 秒)
* 写入 Object,并设定存活时间 单位: 秒
* @param key 键名称
* @param object 值
* @param timeout 存活时间 (值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储)
* @param timeout 存活时间值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储
*/
public void setObject(String key, Object object, long timeout);
void setObject(String key, Object object, long timeout);
/**
* 更新Object (过期时间不变)
* 更新 Object 过期时间不变
* @param key 键名称
* @param object 值
*/
public void updateObject(String key, Object object);
void updateObject(String key, Object object);
/**
* 删除Object
* 删除 Object
* @param key 键名称
*/
public void deleteObject(String key);
void deleteObject(String key);
/**
* 获取Object的剩余存活时间 (单位: 秒)
* @param key 指定key
* @return 这个key的剩余存活时间
* 获取 Object 的剩余存活时间 单位: 秒
* @param key 指定 key
* @return 这个 key 的剩余存活时间
*/
public long getObjectTimeout(String key);
long getObjectTimeout(String key);
/**
* 修改Object的剩余存活时间 (单位: 秒)
* @param key 指定key
* @param timeout 过期时间
* 修改 Object 的剩余存活时间单位: 秒
* @param key 指定 key
* @param timeout 剩余存活时间
*/
public void updateObjectTimeout(String key, long timeout);
void updateObjectTimeout(String key, long timeout);
// --------------------- Session读写 ---------------------
// --------------------- SaSession 读写 (默认复用 Object 读写方法) ---------------------
/**
* 获取Session,如无返空
* 获取 SaSession,如无返空
* @param sessionId sessionId
* @return SaSession
*/
public default SaSession getSession(String sessionId) {
default SaSession getSession(String sessionId) {
return (SaSession)getObject(sessionId);
}
/**
* 写入Session,并设定存活时间 (单位: 秒)
* @param session 要保存的Session对象
* @param timeout 过期时间 (单位: 秒)
* 写入 SaSession,并设定存活时间单位: 秒
* @param session 要保存的 SaSession 对象
* @param timeout 过期时间单位: 秒
*/
public default void setSession(SaSession session, long timeout) {
default void setSession(SaSession session, long timeout) {
setObject(session.getId(), session, timeout);
}
/**
* 更新Session
* @param session 要更新的session对象
* 更新 SaSession
* @param session 要更新的 SaSession 对象
*/
public default void updateSession(SaSession session) {
default void updateSession(SaSession session) {
updateObject(session.getId(), session);
}
/**
* 删除Session
* 删除 SaSession
* @param sessionId sessionId
*/
public default void deleteSession(String sessionId) {
default void deleteSession(String sessionId) {
deleteObject(sessionId);
}
/**
* 获取Session剩余存活时间 (单位: 秒)
* @param sessionId 指定Session
* @return 这个Session的剩余存活时间
* 获取 SaSession 剩余存活时间单位: 秒
* @param sessionId 指定 SaSession
* @return 这个 SaSession 的剩余存活时间
*/
public default long getSessionTimeout(String sessionId) {
default long getSessionTimeout(String sessionId) {
return getObjectTimeout(sessionId);
}
/**
* 修改Session剩余存活时间 (单位: 秒)
* @param sessionId 指定Session
* @param timeout 过期时间
* 修改 SaSession 剩余存活时间单位: 秒
* @param sessionId 指定 SaSession
* @param timeout 剩余存活时间
*/
public default void updateSessionTimeout(String sessionId, long timeout) {
default void updateSessionTimeout(String sessionId, long timeout) {
updateObjectTimeout(sessionId, timeout);
}
@@ -169,12 +193,12 @@ public interface SaTokenDao {
* @param prefix 前缀
* @param keyword 关键字
* @param start 开始处索引
* @param size 获取数量 (-1代表从start处一直取到末尾)
* @param size 获取数量 (-1代表从 start 处一直取到末尾)
* @param sortType 排序类型(true=正序,false=反序)
*
* @return 查询到的数据集合
*/
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType);
List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType);
}
@@ -1,32 +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.dao;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Sa-Token持久层接口 [默认实现类, 基于内存Map]
* @author kong
* Sa-Token 持久层接口默认实现类基于内存 Map,系统重启后数据丢失)
*
* @author click33
* @since 1.10.0
*/
public class SaTokenDaoDefaultImpl implements SaTokenDao {
/**
* 数据集合
* 存储数据集合
*/
public Map<String, Object> dataMap = new ConcurrentHashMap<String, Object>();
public Map<String, Object> dataMap = new ConcurrentHashMap<>();
/**
* 过期时间集合 (单位: 毫秒) , 记录所有key的到期时间 [注意不是剩余存活时间]
* 存储数据过期时间集合单位: 毫秒, 记录所有 key 的到期时间 注意存储的是到期时间,不是剩余存活时间
*/
public Map<String, Long> expireMap = new ConcurrentHashMap<String, Long>();
public Map<String, Long> expireMap = new ConcurrentHashMap<>();
/**
* 构造函数
*/
@@ -121,17 +135,30 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
// ------------------------ Session 读写操作
// 使用接口默认实现
// ------------------------ 过期时间相关操作
// --------- 会话管理
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size, sortType);
}
// ------------------------ 以下是一个定时缓存的简单实现,采用:惰性检查 + 异步循环扫描
// --------- 过期时间相关操作
/**
* 如果指定key已经过期,则立即清除它
* @param key 指定key
* 如果指定key 已经过期,则立即清除它
* @param key 指定 key
*/
void clearKeyByTimeout(String key) {
Long expirationTime = expireMap.get(key);
// 清除条件:如果不为空 && 不是[永不过期] && 已经超过过期时间
// 清除条件:
// 1、数据存在。
// 2、不是 [ 永不过期 ]。
// 3、已经超过过期时间。
if(expirationTime != null && expirationTime != SaTokenDao.NEVER_EXPIRE && expirationTime < System.currentTimeMillis()) {
dataMap.remove(key);
expireMap.remove(key);
@@ -139,23 +166,32 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
}
/**
* 获取指定key的剩余存活时间 (单位:秒)
* 获取指定 key 的剩余存活时间 单位:秒
* @param key 指定 key
* @return 这个 key 的剩余存活时间
*/
long getKeyTimeout(String key) {
// 先检查是否已经过期
// 由于数据过期检测属于惰性扫描,很可能此时这个 key 已经过期状态了,所以这里需要先检查一下
clearKeyByTimeout(key);
// 获取过期时间
// 获取这个 key 的过期时间
Long expire = expireMap.get(key);
// 如果根本没有这个值
// 如果 expire 数据不存在,说明框架没有存储这个 key,此时返回 NOT_VALUE_EXPIRE
if(expire == null) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
// 如果被标注为永不过期
// 如果 expire 被标注为永不过期,则返回 NEVER_EXPIRE
if(expire == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
// ---- 计算剩余时间并返回
// ---- 代码至此,说明这个 key 是有过期时间的,且未过期,那么:
// 计算剩余时间并返回 (过期时间戳 - 当前时间戳) / 1000 转秒
long timeout = (expire - System.currentTimeMillis()) / 1000;
// 小于零时,视为不存在
if(timeout < 0) {
dataMap.remove(key);
@@ -164,12 +200,11 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
}
return timeout;
}
// --------------------- 定时清理过期数据
// --------- 定时清理过期数据
/**
* 执行数据清理的线程
* 执行数据清理的线程引用
*/
public Thread refreshThread;
@@ -177,27 +212,26 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
* 是否继续执行数据清理的线程标记
*/
public volatile boolean refreshFlag;
/**
* 清理所有已经过期的key
* 清理所有已经过期的 key
*/
public void refreshDataMap() {
Iterator<String> keys = expireMap.keySet().iterator();
while (keys.hasNext()) {
clearKeyByTimeout(keys.next());
for (String s : expireMap.keySet()) {
clearKeyByTimeout(s);
}
}
/**
* 初始化定时任务
* 初始化定时任务,定时清理过期数据
*/
public void initRefreshThread() {
// 如果配置了<=0的值,则不启动定时清理
// 如果开发者配置了 <=0 的值,则不启动定时清理
if(SaManager.getConfig().getDataRefreshPeriod() <= 0) {
return;
}
// 启动定时刷新
this.refreshFlag = true;
this.refreshThread = new Thread(() -> {
@@ -205,7 +239,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
try {
try {
// 如果已经被标记为结束
if(refreshFlag == false) {
if( ! refreshFlag) {
return;
}
// 执行清理
@@ -218,7 +252,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
if(dataRefreshPeriod <= 0) {
dataRefreshPeriod = 1;
}
Thread.sleep(dataRefreshPeriod * 1000);
Thread.sleep(dataRefreshPeriod * 1000L);
} catch (Exception e) {
e.printStackTrace();
}
@@ -228,27 +262,10 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
}
/**
* 结束定时任务
* 结束定时任务,不再定时清理过期数据
*/
public void endRefreshThread() {
this.refreshFlag = false;
}
// --------------------- 会话管理
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size, sortType);
}
}
@@ -1,169 +1,186 @@
/*
* 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.error;
/**
* 定义所有异常细分状态码
*
* @author kong
* @since: 2022-10-30
* @author click33
* @since 1.33.0
*/
public interface SaErrorCode {
/** 代表这个异常在抛出时未指定异常细分状态码 */
public static final int CODE_UNDEFINED = -1;
int CODE_UNDEFINED = -1;
// ------------
/** 未能获取有效的上下文处理器 */
public static final int CODE_10001 = 10001;
int CODE_10001 = 10001;
/** 未能获取有效的上下文 */
public static final int CODE_10002 = 10002;
int CODE_10002 = 10002;
/** JSON 转换器未实现 */
public static final int CODE_10003 = 10003;
int CODE_10003 = 10003;
/** 未能从全局 StpLogic 集合中找到对应 type 的 StpLogic */
public static final int CODE_10011 = 10011;
int CODE_10011 = 10011;
/** 指定的配置文件加载失败 */
public static final int CODE_10021 = 10021;
int CODE_10021 = 10021;
/** 配置文件属性无法正常读取 */
public static final int CODE_10022 = 10022;
int CODE_10022 = 10022;
/** 重置的侦听器集合不可以为空 */
public static final int CODE_10031 = 10031;
int CODE_10031 = 10031;
/** 注册的侦听器不可以为空 */
public static final int CODE_10032 = 10032;
int CODE_10032 = 10032;
// 1030x core模块
/** 提供的 Same-Token 是无效的 */
public static final int CODE_10301 = 10301;
int CODE_10301 = 10301;
/** 表示未能通过 Http Basic 认证校验 */
public static final int CODE_10311 = 10311;
int CODE_10311 = 10311;
/** 提供的 HttpMethod 是无效的 */
public static final int CODE_10321 = 10321;
int CODE_10321 = 10321;
// 1100x StpLogic
/** 未能读取到有效Token */
public static final int CODE_11001 = 11001;
int CODE_11001 = 11001;
/** 登录时的账号id值为空 */
public static final int CODE_11002 = 11002;
int CODE_11002 = 11002;
/** 更改 Token 指向的 账号Id 时,账号Id值为空 */
public static final int CODE_11003 = 11003;
int CODE_11003 = 11003;
/** 未能读取到有效Token */
public static final int CODE_11011 = 11011;
int CODE_11011 = 11011;
/** Token无效 */
public static final int CODE_11012 = 11012;
int CODE_11012 = 11012;
/** Token已过期 */
public static final int CODE_11013 = 11013;
int CODE_11013 = 11013;
/** Token已被顶下线 */
public static final int CODE_11014 = 11014;
int CODE_11014 = 11014;
/** Token已被踢下线 */
public static final int CODE_11015 = 11015;
int CODE_11015 = 11015;
/** Token已被冻结 */
int CODE_11016 = 11016;
/** 前端未按照指定的前缀提交 token */
int CODE_11017 = 11017;
/** Token已临时过期 */
public static final int CODE_11016 = 11016;
/** 在未集成 sa-token-jwt 插件时调用 getExtra() 抛出异常 */
public static final int CODE_11031 = 11031;
int CODE_11031 = 11031;
/** 缺少指定的角色 */
public static final int CODE_11041 = 11041;
int CODE_11041 = 11041;
/** 缺少指定的权限 */
public static final int CODE_11051 = 11051;
int CODE_11051 = 11051;
/** 当前账号未通过服务封禁校验 */
public static final int CODE_11061 = 11061;
int CODE_11061 = 11061;
/** 提供要解禁的账号无效 */
public static final int CODE_11062 = 11062;
int CODE_11062 = 11062;
/** 提供要解禁的服务无效 */
public static final int CODE_11063 = 11063;
int CODE_11063 = 11063;
/** 提供要解禁的等级无效 */
public static final int CODE_11064 = 11064;
int CODE_11064 = 11064;
/** 二级认证校验未通过 */
public static final int CODE_11071 = 11071;
int CODE_11071 = 11071;
// ------------
/** 请求中缺少指定的参数 */
public static final int CODE_12001 = 12001;
int CODE_12001 = 12001;
/** 构建 Cookie 时缺少 name 参数 */
public static final int CODE_12002 = 12002;
int CODE_12002 = 12002;
/** 构建 Cookie 时缺少 value 参数 */
public static final int CODE_12003 = 12003;
int CODE_12003 = 12003;
// ------------
/** Base64 编码异常 */
public static final int CODE_12101 = 12101;
int CODE_12101 = 12101;
/** Base64 解码异常 */
public static final int CODE_12102 = 12102;
int CODE_12102 = 12102;
/** URL 编码异常 */
public static final int CODE_12103 = 12103;
int CODE_12103 = 12103;
/** URL 解码异常 */
public static final int CODE_12104 = 12104;
int CODE_12104 = 12104;
/** md5 加密异常 */
public static final int CODE_12111 = 12111;
int CODE_12111 = 12111;
/** sha1 加密异常 */
public static final int CODE_12112 = 12112;
int CODE_12112 = 12112;
/** sha256 加密异常 */
public static final int CODE_12113 = 12113;
int CODE_12113 = 12113;
/** AES 加密异常 */
public static final int CODE_12114 = 12114;
int CODE_12114 = 12114;
/** AES 解密异常 */
public static final int CODE_12115 = 12115;
int CODE_12115 = 12115;
/** RSA 公钥加密异常 */
public static final int CODE_12116 = 12116;
int CODE_12116 = 12116;
/** RSA 私钥加密异常 */
public static final int CODE_12117 = 12117;
int CODE_12117 = 12117;
/** RSA 公钥解密异常 */
public static final int CODE_12118 = 12118;
int CODE_12118 = 12118;
/** RSA 私钥解密异常 */
public static final int CODE_12119 = 12119;
int CODE_12119 = 12119;
// ------------
/** 参与参数签名的秘钥不可为空 */
public static final int CODE_12201 = 12201;
int CODE_12201 = 12201;
/** 给定的签名无效 */
public static final int CODE_12202 = 12202;
int CODE_12202 = 12202;
/** timestamp 超出允许的范围 */
public static final int CODE_12203 = 12203;
int CODE_12203 = 12203;
}
@@ -1,8 +1,27 @@
/*
* 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;
/**
* 一个异常:代表 API 已被禁用
* @author kong
* 一个异常:代表 API 已被禁用
*
* <p> 一般在 API 不合适调用的时候抛出,例如在集成 jwt 模块后调用数据持久化相关方法 </p>
*
* @author click33
* @since 1.28.0
*/
public class ApiDisabledException extends SaTokenException {
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 一个异常:代表停止匹配,直接退出,向前端输出结果
* 一个异常:代表停止匹配,直接退出,向前端输出结果 (框架内部专属异常,一般情况下开发者无需关注)
*
* @author kong
* @author click33
* @since 1.21.0
*/
public class BackResultException extends SaTokenException {
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 一个异常:代表指定账号指定服务已被封禁
* 一个异常:代表指定账号指定服务已被封禁
*
* @author kong
* @author click33
* @since 1.31.0
*/
public class DisableServiceException extends SaTokenException {
@@ -22,32 +38,32 @@ public class DisableServiceException extends SaTokenException {
/**
* 账号类型
*/
private String loginType;
private final String loginType;
/**
* 被封禁的账号id
*/
private Object loginId;
private final Object loginId;
/**
* 具体被封禁的服务
*/
private String service;
private final String service;
/**
* 具体被封禁的等级
*/
private int level;
private final int level;
/**
* 校验时要求低于的等级
*/
private int limitLevel;
private final int limitLevel;
/**
* 封禁剩余时间,单位:秒
*/
private long disableTime;
private final long disableTime;
/**
* 获取:账号类型
@@ -1,25 +0,0 @@
package cn.dev33.satoken.exception;
/**
* <h1> 本类设计已过时,未来版本可能移除此类,请及时更换为 SameTokenInvalidException ,使用方式保持不变 </h1>
* 一个异常:代表提供的 Id-Token 无效
*
* @author kong
*/
@Deprecated
public class IdTokenInvalidException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表提供的 Id-Token 无效
* @param message 异常描述
*/
public IdTokenInvalidException(String message) {
super(message);
}
}
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 一个异常:代表未能获取有效的上下文
* 一个异常:代表框架未能获取有效的上下文
*
* @author kong
* @since 2022-10-29
* @author click33
* @since 1.33.0
*/
public class InvalidContextException extends SaTokenException {
@@ -14,7 +29,7 @@ public class InvalidContextException extends SaTokenException {
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表未能获取有效的上下文
* 一个异常:代表框架未能获取有效的上下文
* @param message 异常描述
*/
public InvalidContextException(String message) {
@@ -1,8 +1,25 @@
/*
* 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;
/**
* 一个异常:代表会话未能通过 Http Basic 认证
* @author kong
* 一个异常:代表会话未能通过 Http Basic 认证校验
*
* @author click33
* @since 1.26.0
*/
public class NotBasicAuthException extends SaTokenException {
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 一个异常:代表组件或方法未被提供有效的实现
*
* @author kong
* @since 2022-10-30
* @author click33
* @since 1.33.0
*/
public class NotImplException extends SaTokenException {
@@ -1,13 +1,30 @@
/*
* 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;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.Arrays;
import java.util.List;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 一个异常:代表会话未能通过登录认证
* @author kong
* 一个异常:代表会话未能通过登录认证校验
*
* @author click33
* @since 1.10.0
*/
public class NotLoginException extends SaTokenException {
@@ -24,40 +41,49 @@ public class NotLoginException extends SaTokenException {
* 因为loginId刚取出的时候类型为String,为了避免两者相比较时不必要的类型转换带来的性能消耗,故在此直接将常量类型设计为String
*/
/** 表示未提供token */
/** 表示未能读取到有效 token */
public static final String NOT_TOKEN = "-1";
public static final String NOT_TOKEN_MESSAGE = "未能读取到有效Token";
public static final String NOT_TOKEN_MESSAGE = "未能读取到有效 token";
/** 表示token无效 */
/** 表示 token 无效 */
public static final String INVALID_TOKEN = "-2";
public static final String INVALID_TOKEN_MESSAGE = "Token无效";
public static final String INVALID_TOKEN_MESSAGE = "token 无效";
/** 表示token已过期 */
/** 表示 token 已过期 */
public static final String TOKEN_TIMEOUT = "-3";
public static final String TOKEN_TIMEOUT_MESSAGE = "Token已过期";
public static final String TOKEN_TIMEOUT_MESSAGE = "token 已过期";
/** 表示token已被顶下线 */
/** 表示 token 已被顶下线 */
public static final String BE_REPLACED = "-4";
public static final String BE_REPLACED_MESSAGE = "Token已被顶下线";
public static final String BE_REPLACED_MESSAGE = "token 已被顶下线";
/** 表示token已被踢下线 */
/** 表示 token 已被踢下线 */
public static final String KICK_OUT = "-5";
public static final String KICK_OUT_MESSAGE = "Token已被踢下线";
public static final String KICK_OUT_MESSAGE = "token 已被踢下线";
/** 表示 token 已被冻结 */
public static final String TOKEN_FREEZE = "-6";
public static final String TOKEN_FREEZE_MESSAGE = "token 已被冻结";
/** 表示 未按照指定前缀提交 token */
public static final String NO_PREFIX = "-7";
public static final String NO_PREFIX_MESSAGE = "未按照指定前缀提交 token";
/** 默认的提示语 */
public static final String DEFAULT_MESSAGE = "当前会话未登录";
/**
* 代表异常token的标志集合
* 代表异常 token 的标志集合
*/
public static final List<String> ABNORMAL_LIST = Arrays.asList(NOT_TOKEN, INVALID_TOKEN, TOKEN_TIMEOUT, BE_REPLACED, KICK_OUT);
public static final List<String> ABNORMAL_LIST =
Arrays.asList(NOT_TOKEN, INVALID_TOKEN, TOKEN_TIMEOUT, BE_REPLACED, KICK_OUT, TOKEN_FREEZE, NO_PREFIX);
/**
* 异常类型
*/
private String type;
private final String type;
/**
* 获取异常类型
@@ -71,7 +97,7 @@ public class NotLoginException extends SaTokenException {
/**
* 账号类型
*/
private String loginType;
private final String loginType;
/**
* 获得账号类型
@@ -80,58 +106,29 @@ public class NotLoginException extends SaTokenException {
public String getLoginType() {
return loginType;
}
/**
* 构造方法创建一个
* @param message 异常消息
* 构造方法创建一个
* @param message 异常消息
* @param loginType 账号类型
* @param type 类型
* @param type 类型
*/
public NotLoginException(String message, String loginType, String type) {
super(message);
super(message);
this.loginType = loginType;
this.type = type;
}
/**
* 静态方法构建一个NotLoginException
* @param loginType 账号类型
* @param type 账号类型
* @return 构建完毕的异常对象
*/
public static NotLoginException newInstance(String loginType, String type) {
return newInstance(loginType, type, null);
}
/**
* 静态方法构建一个NotLoginException
* 静态方法构建一个 NotLoginException
* @param loginType 账号类型
* @param type 账号类型
* @param token 引起异常的Token值
* @return 构建完毕的异常对象
* @param type 未登录场景值
* @param message 异常描述信息
* @param token 引起异常的 token 值,可不填,如果填了会拼接到异常描述信息后面
* @return 构建完毕的异常对象
*/
public static NotLoginException newInstance(String loginType, String type, String token) {
String message = null;
if(NOT_TOKEN.equals(type)) {
message = NOT_TOKEN_MESSAGE;
}
else if(INVALID_TOKEN.equals(type)) {
message = INVALID_TOKEN_MESSAGE;
}
else if(TOKEN_TIMEOUT.equals(type)) {
message = TOKEN_TIMEOUT_MESSAGE;
}
else if(BE_REPLACED.equals(type)) {
message = BE_REPLACED_MESSAGE;
}
else if(KICK_OUT.equals(type)) {
message = KICK_OUT_MESSAGE;
}
else {
message = DEFAULT_MESSAGE;
}
if(SaFoxUtil.isEmpty(token) == false) {
public static NotLoginException newInstance(String loginType, String type, String message, String token) {
if(SaFoxUtil.isNotEmpty(token)) {
message = message + "" + token;
}
return new NotLoginException(message, loginType, type);
@@ -1,12 +1,27 @@
/*
* 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;
import cn.dev33.satoken.stp.StpUtil;
/**
* 一个异常:代表会话未能通过权限认证
* 一个异常:代表会话未能通过权限认证校验
*
* @author kong
*
* @author click33
* @since 1.10.0
*/
public class NotPermissionException extends SaTokenException {
@@ -16,7 +31,7 @@ public class NotPermissionException extends SaTokenException {
private static final long serialVersionUID = 6806129545290130141L;
/** 权限码 */
private String permission;
private final String permission;
/**
* @return 获得具体缺少的权限码
@@ -28,7 +43,7 @@ public class NotPermissionException extends SaTokenException {
/**
* 账号类型
*/
private String loginType;
private final String loginType;
/**
* 获得账号类型
@@ -1,12 +1,27 @@
/*
* 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;
import cn.dev33.satoken.stp.StpUtil;
/**
* 一个异常:代表会话未能通过角色认证
* 一个异常:代表会话未能通过角色认证校验
*
* @author kong
*
* @author click33
* @since 1.10.0
*/
public class NotRoleException extends SaTokenException {
@@ -16,7 +31,7 @@ public class NotRoleException extends SaTokenException {
private static final long serialVersionUID = 8243974276159004739L;
/** 角色标识 */
private String role;
private final String role;
/**
* @return 获得角色标识
@@ -28,7 +43,7 @@ public class NotRoleException extends SaTokenException {
/**
* 账号类型
*/
private String loginType;
private final String loginType;
/**
* 获得账号类型
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 一个异常:代表会话未能通过二级认证校验
*
* @author kong
* @author click33
* @since 1.21.0
*/
public class NotSafeException extends SaTokenException {
@@ -18,17 +34,17 @@ public class NotSafeException extends SaTokenException {
/**
* 账号类型
*/
private String loginType;
private final String loginType;
/**
* 未通过校验的 Token 值
*/
private Object tokenValue;
private final Object tokenValue;
/**
* 未通过校验的服务
*/
private String service;
private final String service;
/**
* 获取:账号类型
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 一个异常:代表不是 Web 上下文
* 一个异常:代表当前不是 Web 上下文,无法调用某个 API
*
* @author kong
* @since 2022-10-29
* @author click33
* @since 1.33.0
*/
public class NotWebContextException extends SaTokenException {
@@ -14,7 +29,7 @@ public class NotWebContextException extends SaTokenException {
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表不是 Web 上下文
* 一个异常:代表当前不是 Web 上下文,无法调用某个 API
* @param message 异常描述
*/
public NotWebContextException(String message) {
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 一个异常:代表 JSON 转换失败
*
* @author kong
* @author click33
* @since 1.30.0
*/
public class SaJsonConvertException extends SaTokenException {
@@ -0,0 +1,63 @@
/*
* 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;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 一个异常:代表 API 参数签名校验失败
*
* @author click33
* @since 1.34.0
*/
public class SaSignException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表 API 参数签名校验失败
* @param message 异常描述
*/
public SaSignException(String message) {
super(message);
}
/**
* 如果flag==true,则抛出message异常
* @param flag 标记
* @param message 异常信息
*/
public static void throwBy(boolean flag, String message) {
if(flag) {
throw new SaSignException(message);
}
}
/**
* 如果 value isEmpty,则抛出 message 异常
* @param value 值
* @param message 异常信息
*/
public static void throwByNull(Object value, String message) {
if(SaFoxUtil.isEmpty(value)) {
throw new SaSignException(message);
}
}
}
@@ -1,14 +1,30 @@
/*
* 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;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token框架内部逻辑发生错误抛出的异常
* (自定义此异常方便开发者在做全局异常处理时分辨异常类型)
*
* @author kong
* Sa-Token 框架内部逻辑发生错误抛出的异常
*
* <p> 框架其它异常均继承自此类,开发者可通过捕获此异常来捕获框架内部抛出的所有异常 </p>
*
* @author click33
* @since 1.10.0
*/
public class SaTokenException extends RuntimeException {
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 一个异常:代表提供的 Same-Token 无效
* 一个异常:代表 Same-Token 校验未通过
*
* @author kong
* @since 2022-10-24
* @author click33
* @since 1.32.0
*/
public class SameTokenInvalidException extends SaTokenException {
@@ -14,7 +29,7 @@ public class SameTokenInvalidException extends SaTokenException {
private static final long serialVersionUID = 6806129545290130144L;
/**
* 一个异常:代表提供的 Same-Token 无效
* 一个异常:代表 Same-Token 校验未通过
* @param message 异常描述
*/
public SameTokenInvalidException(String message) {
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 一个异常:代表停止路由匹配,进入Controller
* 一个异常:代表停止路由匹配,进入 Controller (框架内部专属异常,一般情况下开发者无需关注)
*
* @author kong
* @author click33
* @since 1.20.0
*/
public class StopMatchException extends SaTokenException {
@@ -0,0 +1,85 @@
/*
* 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 java.util.List;
/**
* Sa-Token 过滤器接口,为不同版本的过滤器:
* 1、封装共同代码。
* 2、定义统一的行为接口。
*
* @author click33
* @since 1.34.0
*/
public interface SaFilter {
// ------------------------ 设置此过滤器 拦截 & 放行 的路由
/**
* 添加 [ 拦截路由 ]
* @param paths 路由
* @return 对象自身
*/
SaFilter addInclude(String... paths);
/**
* 添加 [ 放行路由 ]
* @param paths 路由
* @return 对象自身
*/
SaFilter addExclude(String... paths);
/**
* 写入 [ 拦截路由 ] 集合
* @param pathList 路由集合
* @return 对象自身
*/
SaFilter setIncludeList(List<String> pathList);
/**
* 写入 [ 放行路由 ] 集合
* @param pathList 路由集合
* @return 对象自身
*/
SaFilter setExcludeList(List<String> pathList);
// ------------------------ 钩子函数
/**
* 写入[ 认证函数 ]: 每次请求执行
* @param auth see note
* @return 对象自身
*/
SaFilter setAuth(SaFilterAuthStrategy auth);
/**
* 写入[ 异常处理函数 ]:每次[ 认证函数 ]发生异常时执行此函数
* @param error see note
* @return 对象自身
*/
SaFilter setError(SaFilterErrorStrategy error);
/**
* 写入[ 前置函数 ]:在每次[ 认证函数 ]之前执行。
* <b>注意点:前置认证函数将不受 includeList 与 excludeList 的限制,所有路由的请求都会进入 beforeAuth</b>
* @param beforeAuth /
* @return 对象自身
*/
SaFilter setBeforeAuth(SaFilterAuthStrategy beforeAuth);
}
@@ -1,16 +1,33 @@
/*
* 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;
/**
* Sa-Token全局过滤器-认证策略
* @author kong
* Sa-Token 全局过滤器 - 认证策略封装,方便 lambda 表达式风格调用
*
* @author click33
* @since 1.17.0
*/
@FunctionalInterface
public interface SaFilterAuthStrategy {
/**
* 执行方法
* @param r 无含义参数,留作扩展
* @param obj 无含义参数,留作扩展
*/
public void run(Object r);
void run(Object obj);
}
@@ -1,17 +1,36 @@
/*
* 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;
/**
* Sa-Token全局过滤器-异常处理策略
* @author kong
* Sa-Token 全局过滤器 - 异常处理策略封装,方便 lambda 表达式风格调用
*
* <p> 此方法的返回值将在 toString() 后返回给前端,如果你要返回 JSON 数据,需要在返回前自行序列化为 JSON 字符串 </p>
*
* @author click33
* @since 1.16.0
*/
@FunctionalInterface
public interface SaFilterErrorStrategy {
/**
* 执行方法
* @param e 异常对象
* @return 输出对象(请提前序列化)
* @return 输出对象,此返回值将在 toString() 后返回给前端,如果你要返回 JSON 数据,需要在返回前自行序列化为 JSON 字符串
*/
public Object run(Throwable e);
Object run(Throwable e);
}
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 根据Boolean变量,决定是否执行一个函数
* lambda 表达式辅助封装:根据 Boolean 变量,决定是否执行一个函数
*
* @author kong
*
* @author click33
* @since 1.13.0
*/
public class IsRunFunction {
@@ -1,10 +1,25 @@
/*
* 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;
/**
* 设定一个函数,方便在Lambda表达式下的函数式编程
* 无形参、无返回值的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* @author kong
*
* @author click33
* @since 1.13.0
*/
@FunctionalInterface
public interface SaFunction {
@@ -12,6 +27,6 @@ public interface SaFunction {
/**
* 执行的方法
*/
public void run();
void run();
}
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 设定一个函数,并传入一个参数,方便在Lambda表达式下的函数式编程
* @author kong
* 单形参、无返回值的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* @author click33
* @since 1.27.0
*/
@FunctionalInterface
public interface SaParamFunction<T> {
@@ -12,6 +28,6 @@ public interface SaParamFunction<T> {
* 执行的方法
* @param r 传入的参数
*/
public void run(T r);
void run(T r);
}
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 设定一个函数,传入一个参数,并返回一个值,方便在Lambda表达式下的函数式编程
* @author kong
* 单形参、有返回值的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* @author click33
* @since 1.27.0
*/
@FunctionalInterface
public interface SaParamRetFunction<T, R> {
@@ -13,6 +29,6 @@ public interface SaParamRetFunction<T, R> {
* @param param 传入的参数
* @return 返回值
*/
public R run(T param);
R run(T param);
}
@@ -1,9 +1,25 @@
/*
* 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;
/**
* 设定一个函数,并返回一个值,方便在Lambda表达式下的函数式编程
* @author kong
* 无形参、有返回值的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* @author click33
* @since 1.20.0
*/
@FunctionalInterface
public interface SaRetFunction {
@@ -12,6 +28,6 @@ public interface SaRetFunction {
* 执行的方法
* @return 返回值
*/
public Object run();
Object run();
}
@@ -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;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
/**
* 路由拦截器验证方法的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* @author click33
* @since 1.34.0
*/
@FunctionalInterface
public interface SaRouteFunction {
/**
* 执行验证的方法
*
* @param request Request 包装对象
* @param response Response 包装对象
* @param handler 处理对象
*/
void run(SaRequest request, SaResponse response, Object handler);
}
@@ -0,0 +1,33 @@
/*
* 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 java.lang.reflect.AnnotatedElement;
import java.util.function.Consumer;
/**
* 函数式接口:对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)
*
* <p> 参数:element元素 </p>
* <p> 返回:无 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCheckElementAnnotationFunction extends Consumer<AnnotatedElement> {
}
@@ -0,0 +1,33 @@
/*
* 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 java.lang.reflect.Method;
import java.util.function.Consumer;
/**
* 函数式接口:对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)
*
* <p> 参数:Method句柄 </p>
* <p> 返回:无 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCheckMethodAnnotationFunction extends Consumer<Method> {
}
@@ -0,0 +1,34 @@
/*
* 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.annotation.SaCheckOr;
import java.util.function.Consumer;
/**
* 函数式接口:对一个 @SaCheckOr 进行注解校验
*
* <p> 参数:SaCheckOr 注解的实例 </p>
* <p> 返回:无 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCheckOrAnnotationFunction extends Consumer<SaCheckOr> {
}
@@ -0,0 +1,34 @@
/*
* 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.session.SaSession;
import java.util.function.Function;
/**
* 函数式接口:创建 SaSession 的策略
*
* <p> 参数:SessionId </p>
* <p> 返回:SaSession对象 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCreateSessionFunction extends Function<String, SaSession> {
}
@@ -0,0 +1,34 @@
/*
* 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.stp.StpLogic;
import java.util.function.Function;
/**
* 函数式接口:创建 StpLogic 的算法
*
* <p> 参数:账号体系标识 </p>
* <p> 返回:创建好的 StpLogic 对象 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCreateStpLogicFunction extends Function<String, StpLogic> {
}
@@ -0,0 +1,32 @@
/*
* 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 java.util.function.BiFunction;
/**
* 函数式接口:创建 token 的策略
*
* <p> 参数:账号 id、账号类型 </p>
* <p> 返回:token 值 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaCreateTokenFunction extends BiFunction<Object, String, String> {
}
@@ -0,0 +1,49 @@
/*
* 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 java.util.function.Function;
import java.util.function.Supplier;
/**
* 生成唯一式 token 的函数式接口,方便开发者进行 lambda 表达式风格调用
*
* <p> 参数:元素名称, 最大尝试次数, 创建 token 函数, 检查 token 函数 </p>
* <p> 返回:生成的token </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaGenerateUniqueTokenFunction {
/**
* 封装 token 生成、校验的代码,生成唯一式 token
*
* @param elementName 要生成的元素名称,方便抛出异常时组织提示信息
* @param maxTryTimes 最大尝试次数
* @param createTokenFunction 创建 token 的函数
* @param checkTokenFunction 校验 token 是否唯一的函数(返回 true 表示唯一,可用)
* @return 最终生成的唯一式 token
*/
String execute(
String elementName,
int maxTryTimes,
Supplier<String> createTokenFunction,
Function<String, Boolean> checkTokenFunction
);
}
@@ -0,0 +1,34 @@
/*
* 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 java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.function.BiFunction;
/**
* 函数式接口:从元素上获取注解
*
* <p> 参数:element元素,要获取的注解类型 </p>
* <p> 返回:注解对象 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaGetAnnotationFunction extends BiFunction<AnnotatedElement, Class<? extends Annotation> , Annotation> {
}
@@ -0,0 +1,33 @@
/*
* 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 java.util.List;
import java.util.function.BiFunction;
/**
* 函数式接口:判断集合中是否包含指定元素(模糊匹配)
*
* <p> 参数:集合、元素 </p>
* <p> 返回:是否包含 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaHasElementFunction extends BiFunction<List<String>, String, Boolean> {
}
@@ -0,0 +1,34 @@
/*
* 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 java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
/**
* 函数式接口:判断一个 Method 或其所属 Class 是否包含指定注解
*
* <p> 参数:Method、注解 </p>
* <p> 返回:是否包含 </p>
*
* @author click33
* @since 1.35.0
*/
@FunctionalInterface
public interface SaIsAnnotationPresentFunction extends BiFunction<Method, Class<? extends Annotation>, Boolean> {
}
@@ -1,3 +1,18 @@
/*
* 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.json;
import java.util.Map;
@@ -5,24 +20,24 @@ import java.util.Map;
/**
* JSON 转换器
*
* @author kong
*
* @author click33
* @since 1.30.0
*/
public interface SaJsonTemplate {
/**
* 将任意对象转换为 json 字符串
* 将任意对象序列化为 json 字符串
*
* @param obj 对象
* @return 转换后的 json 字符串
*/
public String toJsonString(Object obj);
String toJsonString(Object obj);
/**
* 解析 json 字符串为map对象
* @param jsonStr json字符串
* @return map对象
* 解析 json 字符串为 map 对象
* @param jsonStr json 字符串
* @return map 对象
*/
public Map<String, Object> parseJsonToMap(String jsonStr);
Map<String, Object> parseJsonToMap(String jsonStr);
}
@@ -1,3 +1,18 @@
/*
* 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.json;
import java.util.Map;
@@ -6,29 +21,25 @@ import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.NotImplException;
/**
* JSON 相关操作接口
*
* @author kong
* JSON 转换器,默认实现类
*
* <p> 如果代码断点走到了此默认实现类,说明框架没有注入有效的 JSON 转换器,需要开发者自行实现并注入 </p>
*
* @author click33
* @since 1.30.0
*/
public class SaJsonTemplateDefaultImpl implements SaJsonTemplate {
public static final String ERROR_MESSAGE = "未实现具体的 json 转换器";
/**
* 将任意对象转换为 json 字符串
*/
@Override
public String toJsonString(Object obj) {
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10003);
}
/**
* 将 json 字符串解析为 Map
*/
@Override
public Map<String, Object> parseJsonToMap(String jsonStr) {
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10003);
};
}
}
@@ -1,3 +1,18 @@
/*
* 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.listener;
import java.util.ArrayList;
@@ -11,9 +26,11 @@ import cn.dev33.satoken.stp.StpLogic;
/**
* Sa-Token 事件中心 事件发布器
*
* <p> 提供侦听器注册、事件发布能力 </p>
*
* @author kong
* @since: 2022-8-19
* @author click33
* @since 1.31.0
*/
public class SaTokenEventCenter {
@@ -127,7 +144,7 @@ public class SaTokenEventCenter {
// --------- 事件发布
/**
* 每次登录时触发
* 事件发布:xx 账号登录
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue 本次登录产生的 token 值
@@ -140,7 +157,7 @@ public class SaTokenEventCenter {
}
/**
* 每次注销时触发
* 事件发布:xx 账号注销
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
@@ -152,7 +169,7 @@ public class SaTokenEventCenter {
}
/**
* 每次被踢下线时触发
* 事件发布:xx 账号被踢下线
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
@@ -164,7 +181,7 @@ public class SaTokenEventCenter {
}
/**
* 每次被顶下线时触发
* 事件发布:xx 账号被顶下线
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
@@ -176,7 +193,7 @@ public class SaTokenEventCenter {
}
/**
* 每次被封禁时触发
* 事件发布:xx 账号被封禁
* @param loginType 账号类别
* @param loginId 账号id
* @param service 指定服务
@@ -190,7 +207,7 @@ public class SaTokenEventCenter {
}
/**
* 每次被解封时触发
* 事件发布:xx 账号被解封
* @param loginType 账号类别
* @param loginId 账号id
* @param service 指定服务
@@ -202,7 +219,7 @@ public class SaTokenEventCenter {
}
/**
* 每次打开二级认证时触发
* 事件发布:xx 账号完成二级认证
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
@@ -215,7 +232,7 @@ public class SaTokenEventCenter {
}
/**
* 每次关闭二级认证时触发
* 事件发布:xx 账号关闭二级认证
* @param loginType 账号类别
* @param service 指定服务
* @param tokenValue token值
@@ -227,7 +244,7 @@ public class SaTokenEventCenter {
}
/**
* 每次创建Session时触发
* 事件发布:创建了一个新的 SaSession
* @param id SessionId
*/
public static void doCreateSession(String id) {
@@ -237,7 +254,7 @@ public class SaTokenEventCenter {
}
/**
* 每次注销Session时触发
* 事件发布:一个 SaSession 注销了
* @param id SessionId
*/
public static void doLogoutSession(String id) {
@@ -247,7 +264,7 @@ public class SaTokenEventCenter {
}
/**
* 每次Token续期时触发
* 事件发布:指定 Token 续期成功
*
* @param tokenValue token 值
* @param loginId 账号id
@@ -259,20 +276,19 @@ public class SaTokenEventCenter {
}
}
/**
* 全局组件载入
* @param comtName 组件名称
* @param comtObj 组件对象
* 事件发布:有新的全局组件载入到框架中
* @param compName 组件名称
* @param compObj 组件对象
*/
public static void doRegisterComponent(String comtName, Object comtObj) {
public static void doRegisterComponent(String compName, Object compObj) {
for (SaTokenListener listener : listenerList) {
listener.doRegisterComponent(comtName, comtObj);
listener.doRegisterComponent(compName, compObj);
}
}
/**
* StpLogic 对象替换
* 事件发布:有新的 StpLogic 载入到框架中
* @param stpLogic /
*/
public static void doSetStpLogic(StpLogic stpLogic) {
@@ -282,7 +298,7 @@ public class SaTokenEventCenter {
}
/**
* 载入全局配置
* 事件发布:有新的全局配置载入到框架中
* @param config /
*/
public static void doSetConfig(SaTokenConfig config) {
@@ -1,3 +1,18 @@
/*
* 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.listener;
import cn.dev33.satoken.config.SaTokenConfig;
@@ -6,9 +21,11 @@ import cn.dev33.satoken.stp.StpLogic;
/**
* Sa-Token 侦听器
* <p> 你可以通过实现此接口在用户登陆、退出等关键性操作时进行一些AOP操作
* @author kong
*
* <p> 你可以通过实现此接口在用户登录、退出等关键性操作时进行一些AOP切面操作 </p>
*
* @author click33
* @since 1.17.0
*/
public interface SaTokenListener {
@@ -19,7 +36,7 @@ public interface SaTokenListener {
* @param tokenValue 本次登录产生的 token 值
* @param loginModel 登录参数
*/
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel);
void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel);
/**
* 每次注销时触发
@@ -27,7 +44,7 @@ public interface SaTokenListener {
* @param loginId 账号id
* @param tokenValue token值
*/
public void doLogout(String loginType, Object loginId, String tokenValue);
void doLogout(String loginType, Object loginId, String tokenValue);
/**
* 每次被踢下线时触发
@@ -35,7 +52,7 @@ public interface SaTokenListener {
* @param loginId 账号id
* @param tokenValue token值
*/
public void doKickout(String loginType, Object loginId, String tokenValue);
void doKickout(String loginType, Object loginId, String tokenValue);
/**
* 每次被顶下线时触发
@@ -43,7 +60,7 @@ public interface SaTokenListener {
* @param loginId 账号id
* @param tokenValue token值
*/
public void doReplaced(String loginType, Object loginId, String tokenValue);
void doReplaced(String loginType, Object loginId, String tokenValue);
/**
* 每次被封禁时触发
@@ -53,7 +70,7 @@ public interface SaTokenListener {
* @param level 封禁等级
* @param disableTime 封禁时长,单位: 秒
*/
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime);
void doDisable(String loginType, Object loginId, String service, int level, long disableTime);
/**
* 每次被解封时触发
@@ -61,7 +78,7 @@ public interface SaTokenListener {
* @param loginId 账号id
* @param service 指定服务
*/
public void doUntieDisable(String loginType, Object loginId, String service);
void doUntieDisable(String loginType, Object loginId, String service);
/**
* 每次打开二级认证时触发
@@ -70,7 +87,7 @@ public interface SaTokenListener {
* @param service 指定服务
* @param safeTime 认证时间,单位:秒
*/
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime);
void doOpenSafe(String loginType, String tokenValue, String service, long safeTime);
/**
* 每次关闭二级认证时触发
@@ -78,46 +95,46 @@ public interface SaTokenListener {
* @param tokenValue token值
* @param service 指定服务
*/
public void doCloseSafe(String loginType, String tokenValue, String service);
void doCloseSafe(String loginType, String tokenValue, String service);
/**
* 每次创建Session时触发
* 每次创建 SaSession 时触发
* @param id SessionId
*/
public void doCreateSession(String id);
void doCreateSession(String id);
/**
* 每次注销Session时触发
* 每次注销 SaSession 时触发
* @param id SessionId
*/
public void doLogoutSession(String id);
void doLogoutSession(String id);
/**
* 每次Token续期时触发
* 每次 Token 续期时触发(注意:是 timeout 续期,而不是 active-timeout 续期)
*
* @param tokenValue token 值
* @param loginId 账号id
* @param timeout 续期时间
*/
public void doRenewTimeout(String tokenValue, Object loginId, long timeout);
void doRenewTimeout(String tokenValue, Object loginId, long timeout);
/**
* 全局组件载入
* @param comtName 组件名称
* @param comtObj 组件对象
* @param compName 组件名称
* @param compObj 组件对象
*/
public default void doRegisterComponent(String comtName, Object comtObj) {}
default void doRegisterComponent(String compName, Object compObj) {}
/**
* StpLogic 对象替换
* @param stpLogic /
*/
public default void doSetStpLogic(StpLogic stpLogic) {}
default void doSetStpLogic(StpLogic stpLogic) {}
/**
* 载入全局配置
* @param config /
*/
public default void doSetConfig(SaTokenConfig config) {}
default void doSetConfig(SaTokenConfig config) {}
}
@@ -1,3 +1,18 @@
/*
* 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.listener;
import static cn.dev33.satoken.SaManager.log;
@@ -8,10 +23,10 @@ import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 侦听器实现:Log 打印
* Sa-Token 侦听器的一个实现:Log 打印
*
* @author kong
* @since 2022-11-2
* @author click33
* @since 1.33.0
*/
public class SaTokenListenerForLog implements SaTokenListener {
@@ -20,7 +35,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
log.info("账号 {} 登录成功 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
log.info("账号 {} 登录成功 (loginType={}), 会话凭证 token={}", loginId, loginType, tokenValue);
}
/**
@@ -28,7 +43,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 注销登录 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
log.info("账号 {} 注销登录 (loginType={}), 会话凭证 token={}", loginId, loginType, tokenValue);
}
/**
@@ -36,7 +51,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 被踢下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
log.info("账号 {} 被踢下线 (loginType={}), 会话凭证 token={}", loginId, loginType, tokenValue);
}
/**
@@ -44,7 +59,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 被顶下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
log.info("账号 {} 被顶下线 (loginType={}), 会话凭证 token={}", loginId, loginType, tokenValue);
}
/**
@@ -68,7 +83,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
log.info("Token 二级认证成功, 业务标识={}, 有效期={}秒, Token值={}", service, safeTime, tokenValue);
log.info("token 二级认证成功, 业务标识={}, 有效期={}秒, Token值={}", service, safeTime, tokenValue);
}
/**
@@ -76,7 +91,7 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
log.info("Token 二级认证关闭, 业务标识={}, Token值={}", service, tokenValue);
log.info("token 二级认证关闭, 业务标识={}, Token值={}", service, tokenValue);
}
/**
@@ -100,19 +115,19 @@ public class SaTokenListenerForLog implements SaTokenListener {
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
log.info("Token 续期成功, {} 秒后到期, 帐号={}, Token值={} ", timeout, loginId, tokenValue);
log.info("token 续期成功, {} 秒后到期, 帐号={}, token值={} ", timeout, loginId, tokenValue);
}
/**
* 全局组件载入
* @param comtName 组件名称
* @param comtObj 组件对象
* @param compName 组件名称
* @param compObj 组件对象
*/
@Override
public void doRegisterComponent(String comtName, Object comtObj) {
String canonicalName = comtObj == null ? null : comtObj.getClass().getCanonicalName();
log.info("全局组件 {} 载入成功: {}", comtName, canonicalName);
public void doRegisterComponent(String compName, Object compObj) {
String canonicalName = compObj == null ? null : compObj.getClass().getCanonicalName();
log.info("全局组件 {} 载入成功: {}", compName, canonicalName);
}
/**
@@ -1,3 +1,18 @@
/*
* 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.listener;
import cn.dev33.satoken.stp.SaLoginModel;
@@ -5,10 +20,10 @@ import cn.dev33.satoken.stp.SaLoginModel;
/**
* Sa-Token 侦听器,默认空实现
*
* <p> 对所有事件方法提供空实现,方便开发者通过继承此类快速实现一个可用的侦听器
* <p> 对所有事件方法提供空实现,方便开发者通过继承此类快速实现一个可用的侦听器 </p>
*
* @author kong
* @since: 2022-8-20
* @author click33
* @since 1.31.0
*/
public class SaTokenListenerForSimple implements SaTokenListener {
@@ -1,10 +1,25 @@
/*
* 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.log;
/**
* Sa-Token 日志输出接口
*
* @author kong
* @since 2022-11-1
* @author click33
* @since 1.33.0
*/
public interface SaLog {
@@ -13,41 +28,41 @@ public interface SaLog {
* @param str 日志内容
* @param args 参数列表
*/
public void trace(String str, Object ...args);
void trace(String str, Object ...args);
/**
* 输出 debug 日志
* @param str 日志内容
* @param args 参数列表
*/
public void debug(String str, Object ...args);
void debug(String str, Object ...args);
/**
* 输出 info 日志
* @param str 日志内容
* @param args 参数列表
*/
public void info(String str, Object ...args);
void info(String str, Object ...args);
/**
* 输出 warn 日志
* @param str 日志内容
* @param args 参数列表
*/
public void warn(String str, Object ...args);
void warn(String str, Object ...args);
/**
* 输出 error 日志
* @param str 日志内容
* @param args 参数列表
*/
public void error(String str, Object ...args);
void error(String str, Object ...args);
/**
* 输出 fatal 日志
* @param str 日志内容
* @param args 参数列表
*/
public void fatal(String str, Object ...args);
void fatal(String str, Object ...args);
}
@@ -1,3 +1,18 @@
/*
* 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.log;
import cn.dev33.satoken.SaManager;
@@ -5,18 +20,13 @@ import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.util.StrFormatter;
/**
* Sa-Token 日志实现类 [控制台打印]
* Sa-Token 日志实现类 [ 控制台打印 ]
*
* @author kong
* @since 2022-11-1
* @author click33
* @since 1.33.0
*/
public class SaLogForConsole implements SaLog {
/**
* 日志输出的前缀
*/
public static String LOG_PREFIX = "SaLog -->: ";
/**
* 日志等级
*/
@@ -26,48 +36,107 @@ public class SaLogForConsole implements SaLog {
public static final int warn = 4;
public static final int error = 5;
public static final int fatal = 6;
/**
* 日志输出的前缀
*/
public static String LOG_PREFIX = "SaLog -->: ";
public static String TRACE_PREFIX = "SA [TRACE]-->: ";
public static String DEBUG_PREFIX = "SA [DEBUG]-->: ";
public static String INFO_PREFIX = "SA [INFO] -->: ";
public static String WARN_PREFIX = "SA [WARN] -->: ";
public static String ERROR_PREFIX = "SA [ERROR]-->: ";
public static String FATAL_PREFIX = "SA [FATAL]-->: ";
/**
* 日志输出的颜色
*/
public static String TRACE_COLOR = "\033[39m";
public static String DEBUG_COLOR = "\033[34m";
public static String INFO_COLOR = "\033[32m";
public static String WARN_COLOR = "\033[33m";
public static String ERROR_COLOR = "\033[31m";
public static String FATAL_COLOR = "\033[35m";
public static String DEFAULT_COLOR = "\033[39m";
@Override
public void trace(String str, Object... args) {
println(trace, str, args);
println(trace, TRACE_COLOR, TRACE_PREFIX, str, args);
}
@Override
public void debug(String str, Object... args) {
println(debug, str, args);
println(debug, DEBUG_COLOR, DEBUG_PREFIX, str, args);
}
@Override
public void info(String str, Object... args) {
println(info, str, args);
println(info, INFO_COLOR, INFO_PREFIX, str, args);
}
@Override
public void warn(String str, Object... args) {
println(warn, str, args);
println(warn, WARN_COLOR, WARN_PREFIX, str, args);
}
@Override
public void error(String str, Object... args) {
println(error, str, args);
println(error, ERROR_COLOR, ERROR_PREFIX, str, args);
}
@Override
public void fatal(String str, Object... args) {
println(fatal, str, args);
println(fatal, FATAL_COLOR, FATAL_PREFIX, str, args);
}
/**
* 打印日志到控制台
* @param level 日志等级
* @param level 日志等级
* @param color 颜色编码
* @param prefix 前缀
* @param str 字符串
* @param args 参数列表
*/
public void println(int level, String str, Object... args) {
public void println(int level, String color, String prefix, String str, Object... args) {
SaTokenConfig config = SaManager.getConfig();
if(config.getIsLog() && level >= config.getLogLevelInt()) {
System.out.println(LOG_PREFIX + StrFormatter.format(str, args));
if(config.getIsColorLog() == Boolean.TRUE) {
// 彩色日志
System.out.println(color + prefix + StrFormatter.format(str, args) + DEFAULT_COLOR);
} else {
// 黑白日志
System.out.println(prefix + StrFormatter.format(str, args));
}
}
}
/*
// 三种写法速度对比
// if( config.getIsColorLog() != null && config.getIsColorLog() ) 10亿次,2058ms
// if( config.getIsColorLog() == Boolean.TRUE ) 10亿次,1050ms 最快
// if( Objects.equals(config.getIsColorLog(), Boolean.TRUE) ) 10亿次,1543ms
*/
/*
颜色参考:
DEFAULT 39
BLACK 30
RED 31
GREEN 32
YELLOW 33
BLUE 34
MAGENTA 35
CYAN 36
WHITE 37
BRIGHT_BLACK 90
BRIGHT_RED 91
BRIGHT_GREEN 92
BRIGHT_YELLOW 93
BRIGHT_BLUE 94
BRIGHT_MAGENTA 95
BRIGHT_CYAN 96
BRIGHT_WHITE 97
*/
}
@@ -1,3 +1,18 @@
/*
* 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.router;
import java.util.HashMap;
@@ -11,8 +26,8 @@ import cn.dev33.satoken.exception.SaTokenException;
*
* <p> 参考:Spring - HttpMethod
*
* @author kong
*
* @author click33
* @since 1.27.0
*/
public enum SaHttpMethod {
@@ -34,11 +49,11 @@ public enum SaHttpMethod {
/**
* String 转 enum
* @param method 请求类型
* @return ReqMethod 对象
* @return SaHttpMethod 对象
*/
public static SaHttpMethod toEnum(String method) {
if(method == null) {
throw new SaTokenException("无效Method" + method).setCode(SaErrorCode.CODE_10321);
throw new SaTokenException("Method 不可以是 null").setCode(SaErrorCode.CODE_10321);
}
SaHttpMethod reqMethod = map.get(method.toUpperCase());
if(reqMethod == null) {
@@ -50,7 +65,7 @@ public enum SaHttpMethod {
/**
* String[] 转 enum[]
* @param methods 请求类型数组
* @return ReqMethod 对象
* @return SaHttpMethod 数组
*/
public static SaHttpMethod[] toEnumArray(String... methods) {
SaHttpMethod [] arr = new SaHttpMethod[methods.length];
@@ -1,24 +0,0 @@
package cn.dev33.satoken.router;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
/**
* 路由拦截器验证方法Lambda
*
* @author kong
*
*/
@FunctionalInterface
public interface SaRouteFunction {
/**
* 执行验证的方法
*
* @param request Request包装对象
* @param response Response包装对象
* @param handler 处理对象
*/
public void run(SaRequest request, SaResponse response, Object handler);
}
@@ -1,3 +1,18 @@
/*
* 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.router;
import java.util.List;
@@ -11,9 +26,20 @@ import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.fun.SaParamRetFunction;
/**
* 路由匹配操作工具类
* @author kong
* 路由匹配操作工具类
*
* <p> 提供了一系列的路由匹配操作方法,一般用在全局拦截器、过滤器做路由拦截鉴权。 </p>
* <p> 简单示例: </p>
* <pre>
* // 指定一条 match 规则
* SaRouter
* .match("/**") // 拦截的 path 列表,可以写多个
* .notMatch("/user/doLogin") // 排除掉的 path 列表,可以写多个
* .check(r->StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式
* </pre>
*
* @author click33
* @since 1.27.0
*/
public class SaRouter {
@@ -1,3 +1,18 @@
/*
* 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.router;
import java.util.List;
@@ -11,8 +26,8 @@ import cn.dev33.satoken.fun.SaParamRetFunction;
/**
* 路由匹配操作对象
*
* @author kong
*
* @author click33
* @since 1.27.0
*/
public class SaRouterStaff {
@@ -1,3 +1,18 @@
/*
* 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.same;
import cn.dev33.satoken.SaManager;
@@ -11,8 +26,8 @@ import cn.dev33.satoken.util.SaFoxUtil;
*
* <p> 解决同源系统互相调用时的身份认证校验, 例如:微服务网关请求转发鉴权、微服务RPC调用鉴权
*
* @author kong
* @since 2022-10-24
* @author click33
* @since 1.32.0
*/
public class SaSameTemplate {
@@ -56,7 +71,7 @@ public class SaSameTemplate {
* @param token /
*/
public void checkToken(String token) {
if(isValid(token) == false) {
if( ! isValid(token)) {
token = (token == null ? "" : token);
throw new SameTokenInvalidException("无效Same-Token" + token).setCode(SaErrorCode.CODE_10301);
}
@@ -77,7 +92,7 @@ public class SaSameTemplate {
// 1. 先将当前 Same-Token 写入到 Past-Same-Token 中
String sameToken = getTokenNh();
if(SaFoxUtil.isEmpty(sameToken) == false) {
if( ! SaFoxUtil.isEmpty(sameToken)) {
savePastToken(sameToken, getTokenTimeout());
}
@@ -1,3 +1,18 @@
/*
* 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.same;
import cn.dev33.satoken.SaManager;
@@ -7,8 +22,8 @@ import cn.dev33.satoken.SaManager;
*
* <p> 解决同源系统互相调用时的身份认证校验, 例如:微服务网关请求转发鉴权、微服务RPC调用鉴权
*
* @author kong
* @since 2022-10-24
* @author click33
* @since 1.32.0
*/
public class SaSameUtil {
@@ -1,3 +1,18 @@
/*
* 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.secure;
@@ -29,8 +44,9 @@ import java.security.SecureRandom;
* }
*
* @author Damien Miller
* @since 4.1.1
* @since 1.29.0
*/
@SuppressWarnings("all")
public class BCrypt {
// BCrypt parameters
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
@@ -1,20 +1,33 @@
/*
* 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.secure;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
/**
* Sa-Token Base64工具类
* @author kong
* Sa-Token Base64 工具类
*
* @author click33
* @since 1.14.0
*/
public class SaBase64Util {
private static Base64.Encoder encoder = Base64.getEncoder();
private static Base64.Decoder decoder = Base64.getDecoder();
private static final Base64.Encoder encoder = Base64.getEncoder();
private static final Base64.Decoder decoder = Base64.getDecoder();
/**
* Base64编码,byte[] 转 String
@@ -40,11 +53,7 @@ public class SaBase64Util {
* @return Base64格式字符串
*/
public static String encode(String text){
try {
return encoder.encodeToString(text.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12101);
}
return encoder.encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
/**
@@ -53,11 +62,7 @@ public class SaBase64Util {
* @return 字符串
*/
public static String decode(String base64Text){
try {
return new String(decoder.decode(base64Text), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12101);
}
return new String(decoder.decode(base64Text), StandardCharsets.UTF_8);
}
}
@@ -1,14 +1,29 @@
/*
* 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.secure;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
@@ -18,19 +33,11 @@ import java.util.Base64;
import java.util.HashMap;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
/**
* Sa-Token 常见加密算法工具类
*
* @author kong
*
* @author click33
* @since 1.14.0
*/
public class SaSecureUtil {
@@ -40,12 +47,12 @@ public class SaSecureUtil {
/**
* Base64编码
*/
private static Base64.Encoder encoder = Base64.getEncoder();
private static final Base64.Encoder encoder = Base64.getEncoder();
/**
* Base64解码
*/
private static Base64.Decoder decoder = Base64.getDecoder();
private static final Base64.Decoder decoder = Base64.getDecoder();
// ----------------------- 摘要加密 -----------------------
@@ -118,8 +125,8 @@ public class SaSecureUtil {
byte[] bytes = messageDigest.digest();
StringBuilder builder = new StringBuilder();
String temp;
for (int i = 0; i < bytes.length; i++) {
temp = Integer.toHexString(bytes[i] & 0xFF);
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
builder.append("0");
}
@@ -190,8 +197,7 @@ public class SaSecureUtil {
* 生成加密秘钥
* @param password 秘钥
* @return SecretKeySpec
* @throws NoSuchAlgorithmException
*/
*/
private static SecretKeySpec getSecretKey(final String password) throws NoSuchAlgorithmException {
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
@@ -228,7 +234,7 @@ public class SaSecureUtil {
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
HashMap<String, String> map = new HashMap<String, String>(16);
HashMap<String, String> map = new HashMap<>(16);
map.put("private", encoder.encodeToString(rsaPrivateKey.getEncoded()));
map.put("public", encoder.encodeToString(rsaPublicKey.getEncoded()));
return map;
@@ -382,7 +388,7 @@ public class SaSecureUtil {
// 数据拆分后的组数,余数不为0时加1
int quotient = remainder != 0 ? bytes.length / splitLength + 1 : bytes.length / splitLength;
byte[][] arrays = new byte[quotient][];
byte[] array = null;
byte[] array;
for (int i = 0; i < quotient; i++) {
// 如果是最后一组(quotient-1),同时余数不等于0,就将最后一组设置为remainder的长度
if (i == quotient - 1 && remainder != 0) {
@@ -400,10 +406,10 @@ public class SaSecureUtil {
/** 将字节数组转换成16进制字符串 */
private static String bytesToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer(bytes.length);
String temp = null;
for (int i = 0; i < bytes.length; i++) {
temp = Integer.toHexString(0xFF & bytes[i]);
StringBuilder sb = new StringBuilder(bytes.length);
String temp;
for (byte aByte : bytes) {
temp = Integer.toHexString(0xFF & aByte);
if (temp.length() < 2) {
sb.append(0);
}
@@ -1,25 +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.session;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.application.SaSetValueInterface;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.listener.SaTokenEventCenter;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Session Model,会话作用域的读取值对象
* <p> 在一次会话范围内: 存值、取值
* Session Model,会话作用域的读取值对象
*
* @author kong
* <p> 在一次会话范围内: 存值、取值。数据在注销登录后失效。</p>
* <p>
* 在 Sa-Token 中,SaSession 分为三种,分别是: <br>
* - Account-Session: 指的是框架为每个 账号id 分配的 SaSession。 <br>
* - Token-Session: 指的是框架为每个 token 分配的 SaSession。 <br>
* - Custom-Session: 指的是以一个 特定的值 作为SessionId,来分配的 SaSession。 <br>
* <br>
* 注意:以上分类仅为框架设计层面的概念区分,实际上它们的数据存储格式都是一致的。
* </p>
*
* @author click33
* @since 1.10.0
*/
public class SaSession implements SaSetValueInterface, Serializable {
@@ -29,29 +49,56 @@ public class SaSession implements SaSetValueInterface, Serializable {
private static final long serialVersionUID = 1L;
/**
* 在 Session 上存储用户对象时建议使用的key
* 在 SaSession 上存储用户对象时建议使用的 key
*/
public static final String USER = "USER";
/**
* 在 Session 上存储角色时建议使用的key
* 在 SaSession 上存储角色列表时建议使用的 key
*/
public static final String ROLE_LIST = "ROLE_LIST";
/**
* 在 Session 上存储权限时建议使用的key
* 在 SaSession 上存储权限列表时建议使用的 key
*/
public static final String PERMISSION_LIST = "PERMISSION_LIST";
/** 此 Session 的 id */
/**
* 此 SaSession 的 id
*/
private String id;
/** 此 Session 的创建时间(时间戳) */
/**
* 此 SaSession 的 类型
*/
private String type;
/**
* 所属 loginType
*/
private String loginType;
/**
* 所属 loginId (当此 SaSession 属于 Account-Session 时,此值有效)
*/
private Object loginId;
/**
* 所属 Token (当此 SaSession 属于 Token-Session 时,此值有效)
*/
private String token;
/**
* 此 SaSession 的创建时间(13位时间戳)
*/
private long createTime;
/** 此 Session 的所有挂载数据 */
/**
* 所有挂载数据
*/
private final Map<String, Object> dataMap = new ConcurrentHashMap<>();
// ----------------------- 构建相关
/**
@@ -77,16 +124,16 @@ public class SaSession implements SaSetValueInterface, Serializable {
}
/**
* 获取此 Session 的 id
* @return 此 Session 的id
* 获取SaSession 的 id
* @return /
*/
public String getId() {
return id;
return this.id;
}
/**
* 写入此 Session 的 id
* @param id SessionId
* 写入SaSession 的 id
* @param id /
* @return 对象自身
*/
public SaSession setId(String id) {
@@ -95,16 +142,90 @@ public class SaSession implements SaSetValueInterface, Serializable {
}
/**
* 返回当前会话创建时间(时间戳)
* @return 时间戳
* 获取:此 SaSession 的 类型
*
* @return /
*/
public long getCreateTime() {
return createTime;
public String getType() {
return this.type;
}
/**
* 写入此 Session 的创建时间(时间戳)
* @param createTime 时间戳
* 设置:SaSession 的 类型
*
* @param type /
* @return 对象自身
*/
public SaSession setType(String type) {
this.type = type;
return this;
}
/**
* 获取:所属 loginType
* @return /
*/
public String getLoginType() {
return this.loginType;
}
/**
* 设置:所属 loginType
* @param loginType /
* @return 对象自身
*/
public SaSession setLoginType(String loginType) {
this.loginType = loginType;
return this;
}
/**
* 获取:所属 loginId (当此 SaSession 属于 Account-Session 时,此值有效)
* @return /
*/
public Object getLoginId() {
return this.loginId;
}
/**
* 设置:所属 loginId (当此 SaSession 属于 Account-Session 时,此值有效)
* @param loginId /
* @return 对象自身
*/
public SaSession setLoginId(Object loginId) {
this.loginId = loginId;
return this;
}
/**
* 获取:所属 Token (当此 SaSession 属于 Token-Session 时,此值有效)
* @return /
*/
public String getToken() {
return this.token;
}
/**
* 设置:所属 Token (当此 SaSession 属于 Token-Session 时,此值有效)
* @param token /
* @return 对象自身
*/
public SaSession setToken(String token) {
this.token = token;
return this;
}
/**
* 返回:当前 SaSession 的创建时间(13位时间戳)
* @return /
*/
public long getCreateTime() {
return this.createTime;
}
/**
* 写入:此 SaSession 的创建时间(13位时间戳)
* @param createTime /
* @return 对象自身
*/
public SaSession setCreateTime(long createTime) {
@@ -152,14 +273,15 @@ public class SaSession implements SaSetValueInterface, Serializable {
* @param device 设备类型,填 null 代表不限设备类型
* @return token签名列表
*/
public List<TokenSign> tokenSignListCopyByDevice(String device) {
public List<TokenSign> getTokenSignListByDevice(String device) {
// 返回全部
if(device == null) {
return tokenSignListCopy();
}
// 返回筛选后的
// 返回筛选后的
List<TokenSign> tokenSignList = tokenSignListCopy();
List<TokenSign> list = new ArrayList<>();
for (TokenSign tokenSign : tokenSignListCopy()) {
for (TokenSign tokenSign : tokenSignList) {
if(SaFoxUtil.equals(tokenSign.getDevice(), device)) {
list.add(tokenSign);
}
@@ -167,6 +289,24 @@ public class SaSession implements SaSetValueInterface, Serializable {
return list;
}
/**
* 获取当前 Session 上的所有 token 列表
*
* @param device 设备类型,填 null 代表不限设备类型
* @return 此 loginId 的所有登录 token
*/
public List<String> getTokenValueListByDevice(String device) {
// 遍历解析,按照设备类型进行筛选
List<TokenSign> tokenSignList = tokenSignListCopy();
List<String> tokenValueList = new ArrayList<>();
for (TokenSign tokenSign : tokenSignList) {
if(device == null || tokenSign.getDevice().equals(device)) {
tokenValueList.add(tokenSign.getValue());
}
}
return tokenValueList;
}
/**
* 查找一个 Token 签名
*
@@ -188,13 +328,18 @@ public class SaSession implements SaSetValueInterface, Serializable {
* @param tokenSign Token 签名
*/
public void addTokenSign(TokenSign tokenSign) {
// 如果已经存在于列表中,则无需再次添加
if(getTokenSign(tokenSign.getValue()) != null) {
return;
// 根据 tokenValue 值查重,如果不存在,则添加
TokenSign oldTokenSign = getTokenSign(tokenSign.getValue());
if(oldTokenSign == null) {
tokenSignList.add(tokenSign);
update();
} else {
// 如果存在,则更新
oldTokenSign.setValue(tokenSign.getValue());
oldTokenSign.setDevice(tokenSign.getDevice());
oldTokenSign.setTag(tokenSign.getTag());
update();
}
// 添加并更新
tokenSignList.add(tokenSign);
update();
}
/**
@@ -203,8 +348,9 @@ public class SaSession implements SaSetValueInterface, Serializable {
* @param tokenValue token值
* @param device 设备类型
*/
@Deprecated
public void addTokenSign(String tokenValue, String device) {
addTokenSign(new TokenSign(tokenValue, device));
addTokenSign(new TokenSign(tokenValue, device, null));
}
/**
@@ -219,7 +365,7 @@ public class SaSession implements SaSetValueInterface, Serializable {
}
}
// ----------------------- 一些操作
/**
@@ -291,8 +437,9 @@ public class SaSession implements SaSetValueInterface, Serializable {
protected long trans(long value) {
return value == SaTokenDao.NEVER_EXPIRE ? Long.MAX_VALUE : value;
}
// ----------------------- 存取值 (类型转换)
// ----------------------- 存取值 (类型转换)
// ---- 重写接口方法
@@ -327,7 +474,7 @@ public class SaSession implements SaSetValueInterface, Serializable {
*/
@Override
public SaSession setByNull(String key, Object value) {
if(has(key) == false) {
if( ! has(key)) {
dataMap.put(key, value);
update();
}
@@ -346,19 +493,20 @@ public class SaSession implements SaSetValueInterface, Serializable {
return this;
}
// ---- 其它方法
// ----------------------- 其它方法
/**
* 返回当前Session的所有key
* 返回当前 Session 挂载数据的所有 key
*
* @return 所有值的key列表
* @return key 列表
*/
public Set<String> keys() {
return dataMap.keySet();
}
/**
* 清空所有
* 清空所有挂载数据
*/
public void clear() {
dataMap.clear();
@@ -366,7 +514,7 @@ public class SaSession implements SaSetValueInterface, Serializable {
}
/**
* 获取数据挂载集合(如果更新map里的值,请调用session.update()方法避免产生脏数据
* 获取数据挂载集合(如果更新map里的值,请调用 session.update() 方法避免产生脏数据
*
* @return 返回底层储存值的map对象
*/
@@ -375,7 +523,7 @@ public class SaSession implements SaSetValueInterface, Serializable {
}
/**
* 写入数据集合 (不改变底层对象,只将此dataMap所有数据进行替换)
* 写入数据集合 (不改变底层对象引用,只将此 dataMap 所有数据进行替换)
* @param dataMap 数据集合
*/
public void refreshDataMap(Map<String, Object> dataMap) {
@@ -384,4 +532,18 @@ public class SaSession implements SaSetValueInterface, Serializable {
this.update();
}
//
/**
* 请更换为:getTokenSignListByDevice(device)
*
* @param device 设备类型,填 null 代表不限设备类型
* @return token签名列表
*/
@Deprecated
public List<TokenSign> tokenSignListCopyByDevice(String device) {
return getTokenSignListByDevice(device);
}
}
@@ -1,10 +1,26 @@
/*
* 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.session;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 自定义 Session 工具类
* 自定义 SaSession 工具类,快捷的读取、操作自定义 SaSession
*
* <p>样例:
* <pre>
@@ -18,8 +34,8 @@ import cn.dev33.satoken.strategy.SaStrategy;
* System.out.println("count=" + count);
* </pre>
*
* @author kong
*
* @author click33
* @since 1.10.0
*/
public class SaSessionCustomUtil {
@@ -27,13 +43,13 @@ public class SaSessionCustomUtil {
}
/**
* 添加上指定前缀,防止恶意伪造Session
* 添加上指定前缀,防止恶意伪造数据
*/
public static String sessionKey = "custom";
/**
* 拼接Key: 自定义Session的Id
*
* 拼接Key: 在存储自定义 SaSession 时应该使用的 key
*
* @param sessionId 会话id
* @return sessionId
*/
@@ -42,9 +58,9 @@ public class SaSessionCustomUtil {
}
/**
* 指定keySession是否存在
* 判断:指定 key 的 SaSession 是否存在
*
* @param sessionId Sessionid
* @param sessionId SaSessionid
* @return 是否存在
*/
public static boolean isExists(String sessionId) {
@@ -52,35 +68,36 @@ public class SaSessionCustomUtil {
}
/**
* 获取指定keySession
* 获取指定 key 的 SaSession 对象, 如果此 SaSession 尚未在 DB 创建,isCreate 参数代表是否则新建并返回
*
* @param sessionId key
* @param isCreate 如果此Session尚未在DB创建,是否新建并返回
* @return SaSession
* @param sessionId SaSession 的 id
* @param isCreate 如果此 SaSession 尚未在 DB 创建,是否新建并返回
* @return SaSession 对象
*/
public static SaSession getSessionById(String sessionId, boolean isCreate) {
SaSession session = SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
if (session == null && isCreate) {
session = SaStrategy.me.createSession.apply(splicingSessionKey(sessionId));
session = SaStrategy.instance.createSession.apply(splicingSessionKey(sessionId));
session.setType(SaTokenConsts.SESSION_TYPE__CUSTOM);
SaManager.getSaTokenDao().setSession(session, SaManager.getConfig().getTimeout());
}
return session;
}
/**
* 获取指定keySession, 如果此Session尚未在DB创建,则新建并返回
* 获取指定 key 的 SaSession, 如果此 SaSession 尚未在 DB 创建,则新建并返回
*
* @param sessionId key
* @return session对象
* @param sessionId SaSession 的 id
* @return SaSession 对象
*/
public static SaSession getSessionById(String sessionId) {
return getSessionById(sessionId, true);
}
/**
* 删除指定keySession
* 删除指定 key 的 SaSession
*
* @param sessionId 指定key
* @param sessionId SaSession 的 id
*/
public static void deleteSessionById(String sessionId) {
SaManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
@@ -1,13 +1,29 @@
/*
* 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.session;
import java.io.Serializable;
/**
* Token 签名 Model
* <p>
* 挂在到 SaSession 上的 Token 签名
*
* @author kong
* <p> 挂在到 SaSession 上的 Token 签名,一般情况下,一个 TokenSign 代表一个登录的会话。</p>
*
* @author click33
* @since 1.8.0
*/
public class TokenSign implements Serializable {
@@ -26,6 +42,11 @@ public class TokenSign implements Serializable {
*/
private String device;
/**
* 此客户端登录的挂载数据
*/
private Object tag;
/**
* 构建一个
*/
@@ -37,10 +58,12 @@ public class TokenSign implements Serializable {
*
* @param value Token 值
* @param device 所属设备类型
* @param tag 此客户端登录的挂载数据
*/
public TokenSign(String value, String device) {
public TokenSign(String value, String device, Object tag) {
this.value = value;
this.device = device;
this.tag = tag;
}
/**
@@ -79,10 +102,30 @@ public class TokenSign implements Serializable {
return this;
}
/**
* 获取 此客户端登录的挂载数据
*
* @return /
*/
public Object getTag() {
return this.tag;
}
/**
* 设置 此客户端登录的挂载数据
*
* @param tag /
* @return 对象自身
*/
public TokenSign setTag(Object tag) {
this.tag = tag;
return this;
}
//
@Override
public String toString() {
return "TokenSign [value=" + value + ", device=" + device + "]";
return "TokenSign [value=" + value + ", device=" + device + ", tag=" + tag + "]";
}
}
@@ -1,33 +1,115 @@
/*
* 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.sign;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSignConfig;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaSignException;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.Map;
import java.util.TreeMap;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 参数签名算法
*
* @author kong
* @since: 2022-4-27
* API 参数签名算法,在跨系统接口调用时防参数篡改、防重放攻击。
*
* <p>
* 以 SSO 数据拉取为例,流程大致如下:
* <br> 1. 以 md5( loginId={账号id}8nonce={随机字符串}8timestamp={13位时间戳}8key={secretkey秘钥} ) 生成签名 sign。
* <br> 2. 将 sign 作为参数,拼接到请求地址后面,如:http://xxx.com?loginId=100018nonce=xxx8timestamp=xxx8sign=xxx。
* <br> 3. 服务端接收到请求后,以同样的算法生成一次 sign 。
* <br> 4. 对比两次 sign 是否一致,一致则通过,否则拒绝 。
* </p>
*
* @author click33
* @since 1.30.0
*/
public interface SaSignTemplate {
public class SaSignTemplate {
// ----------- 签名配置
SaSignConfig signConfig;
/**
* 获取:API 签名配置
* @return /
*/
public SaSignConfig getSignConfig() {
return signConfig;
}
/**
* 获取:API 签名配置:
* 1. 如果用户自定义了 signConfig ,则使用用户自定义的。
* 2. 否则使用全局默认配置。
*
* @return /
*/
public SaSignConfig getSignConfigOrGlobal() {
// 如果用户自定义了 signConfig ,则使用用户自定义的
if(signConfig != null) {
return signConfig;
}
// 否则使用全局默认配置
return SaManager.getConfig().getSign();
}
/**
* 获取:API 签名配置的秘钥
* @return /
*/
public String getSecretKey() {
return getSignConfigOrGlobal().getSecretKey();
}
/**
* 设置:API 签名配置
* @param signConfig /
*/
public SaSignTemplate setSignConfig(SaSignConfig signConfig) {
this.signConfig = signConfig;
return this;
}
// ----------- 自定义使用的参数名称 (不声明final,允许开发者自定义修改)
public static String key = "key";
public static String timestamp = "timestamp";
public static String nonce = "nonce";
public static String sign = "sign";
// ----------- 拼接参数
/**
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
public default String joinParams(Map<String, Object> paramsMap) {
public String joinParams(Map<String, ?> paramsMap) {
// 按照 k1=v1&k2=v2&k3=v3 排列
StringBuilder sb = new StringBuilder();
for (String key : paramsMap.keySet()) {
Object value = paramsMap.get(key);
if(SaFoxUtil.isEmpty(value) == false) {
if( ! SaFoxUtil.isEmpty(value) ) {
sb.append(key).append("=").append(value).append("&");
}
}
@@ -46,9 +128,9 @@ public interface SaSignTemplate {
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
public default String joinParamsDictSort(Map<String, Object> paramsMap) {
public String joinParamsDictSort(Map<String, ?> paramsMap) {
// 保证字段按照字典顺序排列
if(paramsMap instanceof TreeMap == false) {
if( ! (paramsMap instanceof TreeMap) ) {
paramsMap = new TreeMap<>(paramsMap);
}
@@ -56,54 +138,49 @@ public interface SaSignTemplate {
return joinParams(paramsMap);
}
// ----------- 创建签名
/**
* 创建签名:md5(paramsStr + keyStr)
* @param paramsMap 参数列表
* @param key 秘钥
* @param paramsMap 参数列表
* @return 签名
*/
public default String createSign(Map<String, Object> paramsMap, String key) {
SaTokenException.throwByNull(key, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
public String createSign(Map<String, ?> paramsMap) {
String secretKey = getSecretKey();
SaSignException.throwByNull(secretKey, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
// 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外
if(paramsMap.containsKey(sign)) {
// 为了保证不影响原有的 paramsMap,此处需要再复制一份
paramsMap = new TreeMap<>(paramsMap);
paramsMap.remove(sign);
}
// 计算签名
String paramsStr = joinParamsDictSort(paramsMap);
String fullStr = paramsStr + "&key=" + key;
String fullStr = paramsStr + "&" + key + "=" + secretKey;
return abstractStr(fullStr);
}
/**
* 使用摘要算法创建签名
* @param fullStr 待摘要的字符串
* @return 签名
*/
public String abstractStr(String fullStr) {
return SaSecureUtil.md5(fullStr);
}
/**
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
* @param paramsMap 参数列表
* @param key 秘钥
* @param sign 待验证的签名
* @return 签名是否有效
*/
public default boolean isValidSign(Map<String, Object> paramsMap, String key, String sign) {
String theSign = createSign(paramsMap, key);
return theSign.equals(sign);
}
/**
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
* @param paramsMap 参数列表
* @param key 秘钥
* @param sign 待验证的签名
*/
public default void checkSign(Map<String, Object> paramsMap, String key, String sign) {
if(isValidSign(paramsMap, key, sign) == false) {
throw new SaTokenException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
}
}
/**
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
* @param paramsMap 参数列表
* @param key 秘钥
* @param paramsMap 参数列表
* @return 加工后的参数列表
*/
public default Map<String, Object> addSignParams(Map<String, Object> paramsMap, String key) {
paramsMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
paramsMap.put("nonce", SaFoxUtil.getRandomString(32));
paramsMap.put("sign", createSign(paramsMap, key));
public Map<String, Object> addSignParams(Map<String, Object> paramsMap) {
paramsMap.put(timestamp, String.valueOf(System.currentTimeMillis()));
paramsMap.put(nonce, SaFoxUtil.getRandomString(32));
paramsMap.put(sign, createSign(paramsMap));
return paramsMap;
}
@@ -111,24 +188,26 @@ public interface SaSignTemplate {
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
* <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
* @param paramsMap 参数列表
* @param key 秘钥
* @return 加工后的参数列表 转化为的参数字符串
* @return 加工后的参数列表 转化为的参数字符串
*/
public default String addSignParamsToString(Map<String, Object> paramsMap, String key) {
// 追加参数
paramsMap = addSignParams(paramsMap, key);
// .
return joinParams(paramsMap);
public String addSignParamsAndJoin(Map<String, Object> paramsMap) {
// 追加参数
paramsMap = addSignParams(paramsMap);
// 拼接参数
return joinParams(paramsMap);
}
// ----------- 校验签名
/**
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
* @param timestamp 待校验的时间戳
* @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
* @return 是否在允许的范围内
*/
public default boolean isValidTimestamp(long timestamp, long allowDisparity) {
public boolean isValidTimestamp(long timestamp) {
long allowDisparity = getSignConfigOrGlobal().getTimestampDisparity();
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
return allowDisparity == -1 || disparity <= allowDisparity;
}
@@ -136,12 +215,143 @@ public interface SaSignTemplate {
/**
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
* @param timestamp 待校验的时间戳
* @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
*/
public default void checkTimestamp(long timestamp, long allowDisparity) {
if(isValidTimestamp(timestamp, allowDisparity) == false) {
throw new SaTokenException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
public void checkTimestamp(long timestamp) {
if( ! isValidTimestamp(timestamp) ) {
throw new SaSignException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
}
}
/**
* 判断:随机字符串 nonce 是否有效。
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
* @param nonce 待判断的随机字符串
* @return 是否有效
*/
public boolean isValidNonce(String nonce) {
// 为空代表无效
if(SaFoxUtil.isEmpty(nonce)) {
return false;
}
// 校验此 nonce 是否已被使用过
String key = splicingNonceSaveKey(nonce);
return SaManager.getSaTokenDao().get(key) == null;
}
/**
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
* @param nonce 待校验的随机字符串
*/
public void checkNonce(String nonce) {
// 为空代表无效
if(SaFoxUtil.isEmpty(nonce)) {
throw new SaSignException("nonce 为空,无效");
}
// 校验此 nonce 是否已被使用过
String key = splicingNonceSaveKey(nonce);
if(SaManager.getSaTokenDao().get(key) != null) {
throw new SaSignException("此 nonce 已被使用过,不可重复使用:" + nonce);
}
// 校验通过后,将此 nonce 保存在缓存中,保证下次校验无法通过
SaManager.getSaTokenDao().set(key, nonce, getSignConfigOrGlobal().getSaveNonceExpire() * 2 + 2);
}
/**
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
* @param paramsMap 参数列表
* @param sign 待验证的签名
* @return 签名是否有效
*/
public boolean isValidSign(Map<String, ?> paramsMap, String sign) {
String theSign = createSign(paramsMap);
return theSign.equals(sign);
}
/**
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
* @param paramsMap 参数列表
* @param sign 待验证的签名
*/
public void checkSign(Map<String, ?> paramsMap, String sign) {
if( ! isValidSign(paramsMap, sign) ) {
throw new SaSignException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
}
}
/**
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
* @param paramMap 待校验的请求参数集合
* @return 是否合法
*/
@SuppressWarnings("all")
public boolean isValidParamMap(Map<String, String> paramMap) {
// 获取必须的三个参数
String timestampValue = paramMap.get(timestamp);
String nonceValue = paramMap.get(nonce);
String signValue = paramMap.get(sign);
// 三个参数必须全部非空
SaSignException.throwByNull(timestampValue, "缺少 timestamp 字段");
SaSignException.throwByNull(nonceValue, "缺少 nonce 字段");
SaSignException.throwByNull(signValue, "缺少 sign 字段");
// 三个值的校验必须全部通过
return isValidTimestamp(Long.parseLong(timestampValue))
&& (getSignConfigOrGlobal().getIsCheckNonce() ? isValidNonce(nonceValue) : true)
&& isValidSign(paramMap, signValue);
}
/**
* 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
* @param paramMap 待校验的请求参数集合
*/
public void checkParamMap(Map<String, String> paramMap) {
// 获取必须的三个参数
String timestampValue = paramMap.get(timestamp);
String nonceValue = paramMap.get(nonce);
String signValue = paramMap.get(sign);
// 依次校验三个参数
checkTimestamp(Long.parseLong(timestampValue));
if(getSignConfigOrGlobal().getIsCheckNonce()) {
checkNonce(nonceValue);
}
checkSign(paramMap, signValue);
// 通过 √
}
/**
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
* @param request 待校验的请求对象
* @return 是否合法
*/
public boolean isValidRequest(SaRequest request) {
return isValidParamMap(request.getParamMap());
}
/**
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
* @param request 待校验的请求对象
*/
public void checkRequest(SaRequest request) {
checkParamMap(request.getParamMap());
}
// ------------------- 返回相应key -------------------
/**
* 拼接key:存储 nonce 时使用的 key
* @param nonce nonce 值
* @return key
*/
public String splicingNonceSaveKey(String nonce) {
return SaManager.getConfig().getTokenName() + ":sign:nonce:" + nonce;
}
}
@@ -1,11 +0,0 @@
package cn.dev33.satoken.sign;
/**
* 参数签名算法 [默认实现类]
*
* @author kong
* @since: 2022-4-27
*/
public class SaSignTemplateDefaultImpl implements SaSignTemplate {
}
@@ -0,0 +1,174 @@
/*
* 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.sign;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
import java.util.Map;
/**
* API 参数签名算法 - 工具类
*
* @author click33
* @since 1.34.0
*/
public class SaSignUtil {
// ----------- 拼接参数
/**
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
public static String joinParams(Map<String, ?> paramsMap) {
return SaManager.getSaSignTemplate().joinParams(paramsMap);
}
/**
* 将所有参数按照字典顺序连接成一个字符串,形如:a=18b=28c=3
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
public static String joinParamsDictSort(Map<String, ?> paramsMap) {
return SaManager.getSaSignTemplate().joinParamsDictSort(paramsMap);
}
// ----------- 创建签名
/**
* 创建签名:md5(paramsStr + keyStr)
* @param paramsMap 参数列表
* @return 签名
*/
public static String createSign(Map<String, ?> paramsMap) {
return SaManager.getSaSignTemplate().createSign(paramsMap);
}
/**
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
* @param paramsMap 参数列表
* @return 加工后的参数列表
*/
public static Map<String, Object> addSignParams(Map<String, Object> paramsMap) {
return SaManager.getSaSignTemplate().addSignParams(paramsMap);
}
/**
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
* <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
* @param paramsMap 参数列表
* @return 加工后的参数列表 转化为的参数字符串
*/
public static String addSignParamsAndJoin(Map<String, Object> paramsMap) {
return SaManager.getSaSignTemplate().addSignParamsAndJoin(paramsMap);
}
// ----------- 校验签名
/**
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
* @param timestamp 待校验的时间戳
* @return 是否在允许的范围内
*/
public static boolean isValidTimestamp(long timestamp) {
return SaManager.getSaSignTemplate().isValidTimestamp(timestamp);
}
/**
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
* @param timestamp 待校验的时间戳
*/
public static void checkTimestamp(long timestamp) {
SaManager.getSaSignTemplate().checkTimestamp(timestamp);
}
/**
* 判断:随机字符串 nonce 是否有效。
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
* @param nonce 待判断的随机字符串
* @return 是否有效
*/
public static boolean isValidNonce(String nonce) {
return SaManager.getSaSignTemplate().isValidNonce(nonce);
}
/**
* 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
* 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
* @param nonce 待校验的随机字符串
*/
public static void checkNonce(String nonce) {
SaManager.getSaSignTemplate().checkNonce(nonce);
}
/**
* 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
* @param paramsMap 参数列表
* @param sign 待验证的签名
* @return 签名是否有效
*/
public static boolean isValidSign(Map<String, ?> paramsMap, String sign) {
return SaManager.getSaSignTemplate().isValidSign(paramsMap, sign);
}
/**
* 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
* @param paramsMap 参数列表
* @param sign 待验证的签名
*/
public static void checkSign(Map<String, ?> paramsMap, String sign) {
SaManager.getSaSignTemplate().checkSign(paramsMap, sign);
}
/**
* 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
* @param paramMap 待校验的请求参数集合
* @return 是否合法
*/
public static boolean isValidParamMap(Map<String, String> paramMap) {
return SaManager.getSaSignTemplate().isValidParamMap(paramMap);
}
/**
* 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
* @param paramMap 待校验的请求参数集合
*/
public static void checkParamMap(Map<String, String> paramMap) {
SaManager.getSaSignTemplate().checkParamMap(paramMap);
}
/**
* 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
* @param request 待校验的请求对象
* @return 是否合法
*/
public static boolean isValidRequest(SaRequest request) {
return SaManager.getSaSignTemplate().isValidRequest(request);
}
/**
* 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
* @param request 待校验的请求对象
*/
public static void checkRequest(SaRequest request) {
SaManager.getSaSignTemplate().checkRequest(request);
}
}
@@ -1,13 +1,35 @@
/*
* 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.stp;
import java.util.Map;
/**
*
* 快速构建 调用 `StpUtil.login()` 时的 [配置参数 Model ]
*
* @author kong
* 快速、简洁的构建:调用 `StpUtil.login()` 时的 [ 配置参数 SaLoginModel ]
*
* <pre>
* // 例如:在登录时指定 token 有效期为七天,代码如下:
* StpUtil.login(10001, SaLoginConfig.setTimeout(60 * 60 * 24 * 7));
*
* // 上面的代码与下面的代码等价
* StpUtil.login(10001, new SaLoginModel().setTimeout(60 * 60 * 24 * 7));
* </pre>
*
* @author click33
* @since 1.29.0
*/
public class SaLoginConfig {
@@ -38,6 +60,14 @@ public class SaLoginConfig {
return create().setTimeout(timeout);
}
/**
* @param activeTimeout 指定此次登录 token 最低活跃频率,单位:秒(如未指定,自动取全局配置的 activeTimeout 值)
* @return 对象自身
*/
public static SaLoginModel setActiveTimeout(long activeTimeout) {
return create().setActiveTimeout(activeTimeout);
}
/**
* @param extraData 扩展信息(只在jwt模式下生效)
* @return 登录参数 Model
@@ -72,6 +102,16 @@ public class SaLoginConfig {
return create().setIsWriteHeader(isWriteHeader);
}
/**
* 设置 本次登录挂载到 TokenSign 的数据
*
* @param tokenSignTag /
* @return 登录参数 Model
*/
public static SaLoginModel setTokenSignTag(Object tokenSignTag) {
return create().setTokenSignTag(tokenSignTag);
}
/**
* 静态方法获取一个 SaLoginModel 对象
* @return SaLoginModel 对象
@@ -1,3 +1,18 @@
/*
* 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.stp;
import java.util.LinkedHashMap;
@@ -9,9 +24,15 @@ import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 调用 `StpUtil.login()` 时的 [配置参数 Model ]
* @author kong
* 调用 `StpUtil.login()` 时的 配置参数 Model,决定登录的一些细节行为 <br>
*
* <pre>
* // 例如:在登录时指定 token 有效期为七天,代码如下:
* StpUtil.login(10001, new SaLoginModel().setTimeout(60 * 60 * 24 * 7));
* </pre>
*
* @author click33
* @since 1.13.2
*/
public class SaLoginModel {
@@ -26,10 +47,15 @@ public class SaLoginModel {
public Boolean isLastingCookie = true;
/**
* 指定此次登录token有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
* 指定此次登录 token 有效期单位秒 (如未指定,自动取全局配置的 timeout 值)
*/
public Long timeout;
/**
* 指定此次登录 token 最低活跃频率,单位:秒(如未指定,则使用全局配置的 activeTimeout 值)
*/
private Long activeTimeout;
/**
* 扩展信息(只在jwt模式下生效)
*/
@@ -42,8 +68,11 @@ public class SaLoginModel {
/** 是否在登录后将 Token 写入到响应头 */
private Boolean isWriteHeader;
/** 本次登录挂载到 TokenSign 的数据 */
private Object tokenSignTag;
/**
* @return 此次登录的客户端设备类型
*/
@@ -67,16 +96,6 @@ public class SaLoginModel {
return isLastingCookie;
}
/**
* @return 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
*/
public Boolean getIsLastingCookieOrFalse() {
if(isLastingCookie == null) {
return false;
}
return isLastingCookie;
}
/**
* @param isLastingCookie 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
* @return 对象自身
@@ -87,24 +106,14 @@ public class SaLoginModel {
}
/**
* @return 指定此次登录token有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
* @return 指定此次登录 token 有效期,单位:秒
*/
public Long getTimeout() {
return timeout;
}
/**
* @return timeout 值 (如果此配置项尚未配置,则取全局配置的值)
*/
public Long getTimeoutOrGlobalConfig() {
if(timeout == null) {
timeout = SaManager.getConfig().getTimeout();
}
return timeout;
}
/**
* @param timeout 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
* @param timeout 指定此次登录 token 有效期,单位:秒 (如未指定,自动取全局配置的 timeout 值)
* @return 对象自身
*/
public SaLoginModel setTimeout(long timeout) {
@@ -112,6 +121,23 @@ public class SaLoginModel {
return this;
}
/**
* @return 此次登录 token 最低活跃频率,单位:秒(如未指定,则使用全局配置的 activeTimeout 值)
*/
public Long getActiveTimeout() {
return activeTimeout;
}
/**
* @param activeTimeout 指定此次登录 token 最低活跃频率,单位:秒(如未指定,则使用全局配置的 activeTimeout 值)
* @return 对象自身
*/
public SaLoginModel setActiveTimeout(long activeTimeout) {
this.activeTimeout = activeTimeout;
return this;
}
/**
* @return 扩展信息(只在jwt模式下生效)
*/
@@ -151,16 +177,6 @@ public class SaLoginModel {
return isWriteHeader;
}
/**
* @return 是否在登录后将 Token 写入到响应头 (如果此配置项尚未配置,则取全局配置的值)
*/
public Boolean getIsWriteHeaderOrGlobalConfig() {
if(isWriteHeader == null) {
isWriteHeader = SaManager.getConfig().getIsWriteHeader();
}
return isWriteHeader;
}
/**
* @param isWriteHeader 是否在登录后将 Token 写入到响应头
* @return 对象自身
@@ -170,6 +186,26 @@ public class SaLoginModel {
return this;
}
/**
* 获取 本次登录挂载到 TokenSign 的数据
*
* @return tokenSignTag 本次登录挂载到 TokenSign 的数据
*/
public Object getTokenSignTag() {
return this.tokenSignTag;
}
/**
* 设置 本次登录挂载到 TokenSign 的数据
*
* @param tokenSignTag 本次登录挂载到 TokenSign 的数据
* @return 对象自身
*/
public SaLoginModel setTokenSignTag(Object tokenSignTag) {
this.tokenSignTag = tokenSignTag;
return this;
}
/*
* toString
*/
@@ -179,14 +215,46 @@ public class SaLoginModel {
+ "device=" + device
+ ", isLastingCookie=" + isLastingCookie
+ ", timeout=" + timeout
+ ", activeTimeout=" + activeTimeout
+ ", extraData=" + extraData
+ ", token=" + token
+ ", isWriteHeader=" + isWriteHeader
+ ", tokenSignTag=" + tokenSignTag
+ "]";
}
// ------ 附加方法
/**
* @return 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
*/
public Boolean getIsLastingCookieOrFalse() {
if(isLastingCookie == null) {
return false;
}
return isLastingCookie;
}
/**
* @return timeout 值 (如果此配置项尚未配置,则取全局配置的值)
*/
public Long getTimeoutOrGlobalConfig() {
if(timeout == null) {
timeout = SaManager.getConfig().getTimeout();
}
return timeout;
}
/**
* @return 是否在登录后将 Token 写入到响应头 (如果此配置项尚未配置,则取全局配置的值)
*/
public Boolean getIsWriteHeaderOrGlobalConfig() {
if(isWriteHeader == null) {
isWriteHeader = SaManager.getConfig().getIsWriteHeader();
}
return isWriteHeader;
}
/**
* 写入扩展数据(只在jwt模式下生效)
@@ -219,17 +287,14 @@ public class SaLoginModel {
* @return /
*/
public boolean isSetExtraData() {
if(extraData == null || extraData.size() == 0) {
return false;
}
return true;
return extraData != null && extraData.size() != 0;
}
/**
* @return Cookie时长
*/
public int getCookieTimeout() {
if(getIsLastingCookieOrFalse() == false) {
if( ! getIsLastingCookieOrFalse()) {
return -1;
}
if(getTimeoutOrGlobalConfig() == SaTokenDao.NEVER_EXPIRE) {
@@ -247,7 +312,7 @@ public class SaLoginModel {
}
return device;
}
/**
* 构建对象,初始化默认值
* @return 对象自身

Some files were not shown because too many files have changed in this diff Show More