Compare commits

..

42 Commits

Author SHA1 Message Date
shengzhang
f5fe7897ee v1.19.0 更新. 2021-05-10 01:48:00 +08:00
shengzhang
041294e790 v1.19.0 更新 2021-05-10 01:29:56 +08:00
shengzhang
0a7a8138b3 sa-token-quick-login 模块完毕 2021-05-09 19:08:44 +08:00
shengzhang
ca2599c528 目录结构重构完成.. 2021-05-05 01:08:00 +08:00
shengzhang
4398a5808c 目录结构重构完成. 2021-05-05 01:03:24 +08:00
shengzhang
9965821b51 目录结构重构完成 2021-05-05 01:02:20 +08:00
shengzhang
5cde169e7f 完善[多账号模式下使用注解鉴权]的文档 2021-05-04 00:51:54 +08:00
shengzhang
479b40b92b 注解鉴权增加LoginKey属性,用于多账号模式下的注解鉴权支持 2021-05-04 00:26:44 +08:00
省长
76dd333c9b !41 注解定制loginKey
Merge pull request !41 from AppleOfGray/dev
2021-05-03 15:44:46 +08:00
shengzhang
e6e53d44d5 整理文档 2021-04-30 23:48:12 +08:00
shengzhang
3c429cbee9 Merge branch 'dev' of https://github.com/dromara/sa-token into dev 2021-04-30 16:51:41 +08:00
省长
8b8c01a76d !42 update sa-token-doc/doc/use/route-check.md.
Merge pull request !42 from 知知/N/A
2021-04-30 15:47:56 +08:00
知知
9465357d6b update sa-token-doc/doc/use/route-check.md. 2021-04-28 18:27:02 +08:00
省长
fb4733792d !40 update sa-token-doc/doc/start/webflux-example.md.
Merge pull request !40 from AppleOfGray/N/A
2021-04-27 21:56:48 +08:00
省长
a75d461275 !39 update sa-token-doc/doc/start/example.md.
Merge pull request !39 from AppleOfGray/N/A
2021-04-27 21:56:11 +08:00
hjc
9c1ff87023 实现方案二:
在原来的检测登录,检测权限,检测角色注解中
每个都添加一个唯一loginKey,
根据loginKey分别鉴权
2021-04-27 15:48:11 +08:00
AppleOfGray
6d164a0726 update sa-token-doc/doc/start/webflux-example.md. 2021-04-27 15:29:20 +08:00
AppleOfGray
2bb2248522 update sa-token-doc/doc/start/example.md. 2021-04-27 15:28:55 +08:00
hjc
a69e41b04c 多账号体系下就不能再一个stpLogic里面鉴别所有权限了
抽离最小鉴定单位并在外部统一鉴权
2021-04-27 10:03:35 +08:00
hjc
2d4267b1da 序列号重复
添加未识别loginKey异常
删除StpUtil单账户体系默认loginKey相关代码
2021-04-27 09:28:14 +08:00
省长
3405188531 !38 添加token有效期定制设置的提示信息
Merge pull request !38 from AppleOfGray/N/A
2021-04-26 15:07:16 +08:00
省长
7a6d027d59 !37 token过期时间定制登录说明
Merge pull request !37 from AppleOfGray/N/A
2021-04-26 15:06:34 +08:00
AppleOfGray
eae7f9ffbf 添加token有效期定制设置的提示信息 2021-04-26 14:32:01 +08:00
AppleOfGray
865a280365 token过期时间定制登录说明 2021-04-26 14:30:07 +08:00
click33
b34aed5f97 Merge pull request #77 from liutaoyibeizhanyong/patch-3
Update README.md
2021-04-26 10:26:53 +08:00
liutaoyibeizhanyong
cd99053640 Update README.md
修改格式
2021-04-26 08:27:10 +08:00
省长
c0eeaa6ddd !36 update sa-token-doc/doc/use/route-check.md.
Merge pull request !36 from 凯凯大魔王/N/A
2021-04-25 22:49:55 +08:00
凯凯大魔王
72530a223a update sa-token-doc/doc/use/route-check.md. 2021-04-25 19:11:20 +08:00
shengzhang
ec42359377 增加案例 2021-04-25 00:39:43 +08:00
shengzhang
d01db3442b v1.18.0 更新 2021-04-24 00:53:39 +08:00
shengzhang
4ee161031f Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev
# Conflicts:
#	sa-token-core/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java
2021-04-23 19:50:14 +08:00
shengzhang
79d7967e0d 重构 2021-04-23 19:46:37 +08:00
省长
d139bfd858 !35 update sa-token-core/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java.getSessionById
Merge pull request !35 from xingenhi/N/A
2021-04-21 18:57:10 +08:00
xingenhi
f2454dd244 update sa-token-core/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java.getSessionById 2021-04-21 18:56:15 +08:00
省长
9a2e14d147 !33 注销登录中清理token-session
Merge pull request !33 from 八天飞雪/dev
2021-04-19 15:57:38 +08:00
zyh
b7d1ca88af 注销登录中清理token-session 2021-04-19 14:38:25 +08:00
省长
36744a64ee !32 添加开源RP
Merge pull request !32 from 青年/dev
2021-04-19 14:13:08 +08:00
青年
377801d800 修改doc 2021-04-19 13:36:34 +08:00
省长
6d301a0a69 !31 添加开源RP
Merge pull request !31 from 青年/dev
2021-04-19 09:17:22 +08:00
青年
26cde5d244 !1 提交dcy-fast开源rp
Merge pull request !1 from 青年/N/A
2021-04-19 09:15:07 +08:00
青年
5269e30331 提交dcy-fast开源rp 2021-04-19 09:08:31 +08:00
shengzhang
e40a39e3ef 新增权限通配符 2021-04-18 17:06:22 +08:00
190 changed files with 2058 additions and 509 deletions

2
.gitignore vendored
View File

@@ -11,4 +11,4 @@ unpackage/
.factorypath
/.factorypath
.idea/
.idea/

View File

@@ -1,7 +1,7 @@
<p align="center">
<img alt="logo" src="https://gitee.com/dromara/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.17.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.19.0</h1>
<h4 align="center">这可能是史上功能最全的 Java 权限认证框架!</h4>
<h4 align="center">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
@@ -150,6 +150,7 @@ sa-token秉承着开放的思想欢迎大家为框架添砖加瓦
[**[ jthink]** 一个基于springboot+sa-token+thymeleaf的博客系统](https://gitee.com/wtsoftware/jthink)
[**[ dcy-fast]** 一个基于springboot+sa-token+mybatis-plus的后台管理系统前端vue-element-admin并且内置代码生成器](https://gitee.com/dcy421/dcy-fast)
如果您的项目使用了sa-token欢迎提交pr

View File

@@ -1,6 +1,10 @@
:: 整体clean
call mvn clean
:: demo模块clean
cd sa-token-demo
cd sa-token-demo-jwt
call mvn clean
cd ..
@@ -13,14 +17,21 @@ cd sa-token-demo-webflux
call mvn clean
cd ..
cd sa-token-demo-oauth2\sa-token-demo-oauth2-client
cd sa-token-demo-oauth2-client
call mvn clean
cd ../..
cd ..
cd sa-token-demo-oauth2\sa-token-demo-oauth2-server
cd sa-token-demo-oauth2-server
call mvn clean
cd ../..
cd ..
cd sa-token-demo-quick-login
call mvn clean
cd ..
cd ..
:: 最后打印
echo;
echo;
echo ----------- clean end -----------

14
pom.xml
View File

@@ -8,7 +8,7 @@
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<packaging>pom</packaging>
<version>1.17.0</version>
<version>1.19.0</version>
<!-- 项目介绍 -->
<name>sa-token</name>
@@ -19,13 +19,9 @@
<!-- 所有模块 -->
<modules>
<module>sa-token-core</module>
<module>sa-token-servlet</module>
<module>sa-token-spring-boot-starter</module>
<module>sa-token-reactor-spring-boot-starter</module>
<module>sa-token-dao-redis</module>
<module>sa-token-dao-redis-jackson</module>
<module>sa-token-spring-aop</module>
<!-- <module>sa-token-oauth2</module> -->
<module>sa-token-starter</module>
<module>sa-token-plugin</module>
<!-- <module>sa-token-demo\sa-token-demo-quick-login</module> -->
</modules>
<!-- 开源协议 apache 2.0 -->
@@ -40,7 +36,7 @@
<!-- 一些属性 -->
<properties>
<sa-token-version>1.17.0</sa-token-version>
<sa-token-version>1.19.0</sa-token-version>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</parent>
<packaging>jar</packaging>

View File

@@ -11,33 +11,37 @@ import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.SaTokenContextDefaultImpl;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.listener.SaTokenListenerDefaultImpl;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaTokenInsideUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 管理sa-token所有接口对象
* @author kong
*
*/
public class SaTokenManager {
public class SaManager {
/**
* 配置文件 Bean
*/
private static SaTokenConfig config;
public static void setConfig(SaTokenConfig config) {
SaTokenManager.config = config;
SaManager.config = config;
if(config.getIsV()) {
SaTokenInsideUtil.printSaToken();
SaFoxUtil.printSaToken();
}
// 调用一次StpUtil中的方法保证其可以尽早的初始化 StpLogic
StpUtil.getLoginKey();
}
public static SaTokenConfig getConfig() {
if (config == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (config == null) {
setConfig(SaTokenConfigFactory.createConfig());
}
@@ -51,14 +55,14 @@ public class SaTokenManager {
*/
private static SaTokenDao saTokenDao;
public static void setSaTokenDao(SaTokenDao saTokenDao) {
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshThread();
if(SaManager.saTokenDao != null && (SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
}
SaTokenManager.saTokenDao = saTokenDao;
SaManager.saTokenDao = saTokenDao;
}
public static SaTokenDao getSaTokenDao() {
if (saTokenDao == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (saTokenDao == null) {
setSaTokenDao(new SaTokenDaoDefaultImpl());
}
@@ -72,11 +76,11 @@ public class SaTokenManager {
*/
private static StpInterface stpInterface;
public static void setStpInterface(StpInterface stpInterface) {
SaTokenManager.stpInterface = stpInterface;
SaManager.stpInterface = stpInterface;
}
public static StpInterface getStpInterface() {
if (stpInterface == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (stpInterface == null) {
setStpInterface(new StpInterfaceDefaultImpl());
}
@@ -90,11 +94,11 @@ public class SaTokenManager {
*/
private static SaTokenAction saTokenAction;
public static void setSaTokenAction(SaTokenAction saTokenAction) {
SaTokenManager.saTokenAction = saTokenAction;
SaManager.saTokenAction = saTokenAction;
}
public static SaTokenAction getSaTokenAction() {
if (saTokenAction == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (saTokenAction == null) {
setSaTokenAction(new SaTokenActionDefaultImpl());
}
@@ -108,11 +112,11 @@ public class SaTokenManager {
*/
private static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
SaTokenManager.saTokenContext = saTokenContext;
SaManager.saTokenContext = saTokenContext;
}
public static SaTokenContext getSaTokenContext() {
if (saTokenContext == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (saTokenContext == null) {
setSaTokenContext(new SaTokenContextDefaultImpl());
}
@@ -126,11 +130,11 @@ public class SaTokenManager {
*/
private static SaTokenListener saTokenListener;
public static void setSaTokenListener(SaTokenListener saTokenListener) {
SaTokenManager.saTokenListener = saTokenListener;
SaManager.saTokenListener = saTokenListener;
}
public static SaTokenListener getSaTokenListener() {
if (saTokenListener == null) {
synchronized (SaTokenManager.class) {
synchronized (SaManager.class) {
if (saTokenListener == null) {
setSaTokenListener(new SaTokenListenerDefaultImpl());
}
@@ -153,12 +157,31 @@ public class SaTokenManager {
}
/**
* 根据 LoginKey 获取对应的StpLogic如果不存在则返回null
* 根据 LoginKey 获取对应的StpLogic如果不存在则抛出异常
* @param loginKey 对应的LoginKey
* @return 对应的StpLogic
*/
public static StpLogic getStpLogic(String loginKey) {
return stpLogicMap.get(loginKey);
// 如果key为空则返回框架内置的
if(loginKey == null || loginKey.isEmpty()) {
return StpUtil.stpLogic;
}
// 从SaManager中获取
StpLogic stpLogic = stpLogicMap.get(loginKey);
if(stpLogic == null) {
/*
* 此时有两种情况会造成 StpLogic == null
* 1. LoginKey拼写错误请改正 建议使用常量
* 2. 自定义StpUtil尚未初始化静态类中的属性至少一次调用后才会初始化解决方法两种
* (1) 从main方法里调用一次
* (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
*/
throw new SaTokenException("未能获取对应StpLogickey="+ loginKey);
}
// 返回
return stpLogic;
}

View File

@@ -1,5 +1,8 @@
package cn.dev33.satoken.action;
import java.lang.reflect.Method;
import java.util.List;
import cn.dev33.satoken.session.SaSession;
/**
@@ -25,4 +28,18 @@ public interface SaTokenAction {
*/
public SaSession createSession(String sessionId);
/**
* 指定集合是否包含指定元素(模糊匹配)
* @param list 集合
* @param element 元素
* @return 是否包含
*/
public boolean hasElement(List<String> list, String element);
/**
* 对一个Method对象进行注解检查注解鉴权内部实现
* @param method Method对象
*/
public void checkMethodAnnotation(Method method);
}

View File

@@ -1,11 +1,16 @@
package cn.dev33.satoken.action;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import cn.dev33.satoken.util.SaTokenInsideUtil;
/**
* 对 SaTokenAction 接口的默认实现
@@ -14,14 +19,13 @@ import cn.dev33.satoken.util.SaTokenInsideUtil;
*/
public class SaTokenActionDefaultImpl implements SaTokenAction {
/**
* 根据一定的算法生成一个token
*/
@Override
public String createToken(Object loginId, String loginKey) {
// 根据配置的tokenStyle生成不同风格的token
String tokenStyle = SaTokenManager.getConfig().getTokenStyle();
String tokenStyle = SaManager.getConfig().getTokenStyle();
// uuid
if(SaTokenConsts.TOKEN_STYLE_UUID.equals(tokenStyle)) {
return UUID.randomUUID().toString();
@@ -32,25 +36,24 @@ public class SaTokenActionDefaultImpl implements SaTokenAction {
}
// 32位随机字符串
if(SaTokenConsts.TOKEN_STYLE_RANDOM_32.equals(tokenStyle)) {
return SaTokenInsideUtil.getRandomString(32);
return SaFoxUtil.getRandomString(32);
}
// 64位随机字符串
if(SaTokenConsts.TOKEN_STYLE_RANDOM_64.equals(tokenStyle)) {
return SaTokenInsideUtil.getRandomString(64);
return SaFoxUtil.getRandomString(64);
}
// 128位随机字符串
if(SaTokenConsts.TOKEN_STYLE_RANDOM_128.equals(tokenStyle)) {
return SaTokenInsideUtil.getRandomString(128);
return SaFoxUtil.getRandomString(128);
}
// tik风格 (2_14_16)
if(SaTokenConsts.TOKEN_STYLE_TIK.equals(tokenStyle)) {
return SaTokenInsideUtil.getRandomString(2) + "_" + SaTokenInsideUtil.getRandomString(14) + "_" + SaTokenInsideUtil.getRandomString(16) + "__";
return SaFoxUtil.getRandomString(2) + "_" + SaFoxUtil.getRandomString(14) + "_" + SaFoxUtil.getRandomString(16) + "__";
}
// 默认还是uuid
return UUID.randomUUID().toString();
}
/**
* 根据 SessionId 创建一个 Session
*/
@@ -58,5 +61,72 @@ public class SaTokenActionDefaultImpl implements SaTokenAction {
public SaSession createSession(String sessionId) {
return new SaSession(sessionId);
}
/**
* 指定集合是否包含指定元素(模糊匹配)
*/
@Override
public boolean hasElement(List<String> list, String element) {
// 集合为空直接返回false
if(list == null || list.size() == 0) {
return false;
}
// 遍历匹配
for (String patt : list) {
if(SaFoxUtil.vagueMatch(patt, element)) {
return true;
}
}
// 走出for循环说明没有一个元素可以匹配成功
return false;
}
/**
* 对一个Method对象进行注解权限校验注解鉴权逻辑内部实现
*/
@Override
public void checkMethodAnnotation(Method method) {
// 获取这个 Method 所属的 Class
Class<?> clazz = method.getDeclaringClass();
// 从 Class 校验 @SaCheckLogin 注解
if(clazz.isAnnotationPresent(SaCheckLogin.class)) {
SaCheckLogin at = clazz.getAnnotation(SaCheckLogin.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
// 从 Class 校验 @SaCheckRole 注解
if(clazz.isAnnotationPresent(SaCheckRole.class)) {
SaCheckRole at = clazz.getAnnotation(SaCheckRole.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
// 从 Class 校验 @SaCheckPermission 注解
if(clazz.isAnnotationPresent(SaCheckPermission.class)) {
SaCheckPermission at = clazz.getAnnotation(SaCheckPermission.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
// 从 Method 校验 @SaCheckLogin 注解
if(method.isAnnotationPresent(SaCheckLogin.class)) {
SaCheckLogin at = method.getAnnotation(SaCheckLogin.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
// 从 Method 校验 @SaCheckRole 注解
if(method.isAnnotationPresent(SaCheckRole.class)) {
SaCheckRole at = method.getAnnotation(SaCheckRole.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
// 从 Method 校验 @SaCheckPermission 注解
if(method.isAnnotationPresent(SaCheckPermission.class)) {
SaCheckPermission at = method.getAnnotation(SaCheckPermission.class);
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
}
}
}

View File

@@ -15,4 +15,10 @@ import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckLogin {
/**
* 多账号体系下所属的账号体系标识
* @return see note
*/
String key() default "";
}

View File

@@ -26,5 +26,11 @@ public @interface SaCheckPermission {
* @return 验证模式
*/
SaMode mode() default SaMode.AND;
/**
* 多账号体系下所属的账号体系标识
* @return see note
*/
String key() default "";
}

View File

@@ -26,5 +26,11 @@ public @interface SaCheckRole {
* @return 验证模式
*/
SaMode mode() default SaMode.AND;
/**
* 多账号体系下所属的账号体系标识
* @return see note
*/
String key() default "";
}

View File

@@ -333,8 +333,6 @@ public class SaTokenConfig {
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain
+ ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + ", isLog=" + isLog + "]";
}

View File

@@ -0,0 +1,42 @@
package cn.dev33.satoken.context;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
/**
* Sa-Token 上下文持有类
* @author kong
*
*/
public class SaHolder {
/**
* 获取当前请求的 [Request] 对象
*
* @return see note
*/
public static SaRequest getRequest() {
return SaManager.getSaTokenContext().getRequest();
}
/**
* 获取当前请求的 [Response] 对象
*
* @return see note
*/
public static SaResponse getResponse() {
return SaManager.getSaTokenContext().getResponse();
}
/**
* 获取当前请求的 [存储器] 对象
*
* @return see note
*/
public static SaStorage getStorage() {
return SaManager.getSaTokenContext().getStorage();
}
}

View File

@@ -35,9 +35,15 @@ public interface SaRequest {
public String getCookieValue(String name);
/**
* 返回当前请求的URL
* 返回当前请求path (不包括上下文名称)
* @return see note
*/
public String getRequestURI();
public String getRequestPath();
/**
* 返回当前请求的类型
* @return see note
*/
public String getMethod();
}

View File

@@ -29,4 +29,21 @@ public interface SaResponse {
*/
public void addCookie(String name, String value, String path, String domain, int timeout);
/**
* 在响应头里写入一个值
* @param name 名字
* @param value 值
* @return 对象自身
*/
public SaResponse setHeader(String name, String value);
/**
* 在响应头写入 [Server] 服务器名称
* @param value 服务器名称
* @return 对象自身
*/
public default SaResponse setServer(String value) {
return this.setHeader("Server", value);
}
}

View File

@@ -6,8 +6,8 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.util.SaTokenInsideUtil;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* sa-token持久层默认的实现类 , 基于内存Map
@@ -189,7 +189,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
public void initRefreshThread() {
// 如果配置了<=0的值则不启动定时清理
if(SaTokenManager.getConfig().getDataRefreshPeriod() <= 0) {
if(SaManager.getConfig().getDataRefreshPeriod() <= 0) {
return;
}
// 启动定时刷新
@@ -208,7 +208,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
e.printStackTrace();
}
// 休眠N秒
int dataRefreshPeriod = SaTokenManager.getConfig().getDataRefreshPeriod();
int dataRefreshPeriod = SaManager.getConfig().getDataRefreshPeriod();
if(dataRefreshPeriod <= 0) {
dataRefreshPeriod = 1;
}
@@ -235,7 +235,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
@Override
public List<String> searchData(String prefix, String keyword, int start, int size) {
return SaTokenInsideUtil.searchList(expireMap.keySet(), prefix, keyword, start, size);
return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size);
}

View File

@@ -13,7 +13,7 @@ public class NotPermissionException extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130142L;
private static final long serialVersionUID = 6806129545290130141L;
/** 权限码 */
private String code;

View File

@@ -44,7 +44,6 @@ public class NotRoleException extends SaTokenException {
}
public NotRoleException(String role, String loginKey) {
// 这里到底要不要拼接上loginKey呢纠结
super("无此角色:" + role);
this.role = role;
this.loginKey = loginKey;

View File

@@ -6,6 +6,7 @@ package cn.dev33.satoken.fun;
* @author kong
*
*/
@FunctionalInterface
public interface SaFunction {
/**

View File

@@ -2,9 +2,9 @@ package cn.dev33.satoken.listener;
import java.util.Date;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.util.SaTokenInsideUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 侦听器的默认实现log打印
@@ -51,7 +51,7 @@ public class SaTokenListenerDefaultImpl implements SaTokenListener {
@Override
public void doDisable(String loginKey, Object loginId, long disableTime) {
Date date = new Date(System.currentTimeMillis() + disableTime * 1000);
println("账号[" + loginId + "]被封禁 (解封时间: " + SaTokenInsideUtil.formatDate(date) + ")");
println("账号[" + loginId + "]被封禁 (解封时间: " + SaFoxUtil.formatDate(date) + ")");
}
/**
@@ -88,7 +88,7 @@ public class SaTokenListenerDefaultImpl implements SaTokenListener {
* @param str 字符串
*/
public void println(String str) {
if(SaTokenManager.getConfig().getIsLog()) {
if(SaManager.getConfig().getIsLog()) {
System.out.println(LOG_PREFIX + str);
}
}

View File

@@ -9,6 +9,7 @@ import cn.dev33.satoken.context.model.SaResponse;
* @author kong
*
*/
@FunctionalInterface
public interface SaRouteFunction {
/**

View File

@@ -3,7 +3,8 @@ package cn.dev33.satoken.router;
import java.util.Arrays;
import java.util.List;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.fun.IsRunFunction;
import cn.dev33.satoken.fun.SaFunction;
@@ -23,7 +24,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatch(String pattern, String path) {
return SaTokenManager.getSaTokenContext().matchPath(pattern, path);
return SaManager.getSaTokenContext().matchPath(pattern, path);
}
/**
@@ -47,7 +48,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatchCurrURI(String pattern) {
return isMatch(pattern, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
return isMatch(pattern, SaHolder.getRequest().getRequestPath());
}
/**
@@ -56,7 +57,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatchCurrURI(List<String> patterns) {
return isMatch(patterns, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
return isMatch(patterns, SaHolder.getRequest().getRequestPath());
}
@@ -119,7 +120,7 @@ public class SaRouterUtil {
* @return 匹配结果包装对象
*/
public static IsRunFunction match(String... patterns) {
boolean matchResult = isMatch(Arrays.asList(patterns), SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
boolean matchResult = isMatch(Arrays.asList(patterns), SaHolder.getRequest().getRequestPath());
return new IsRunFunction(matchResult);
}

View File

@@ -7,7 +7,7 @@ import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
/**
* Session Model
@@ -45,7 +45,7 @@ public class SaSession implements Serializable {
this.id = id;
this.createTime = System.currentTimeMillis();
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doCreateSession(id);
SaManager.getSaTokenListener().doCreateSession(id);
}
/**
@@ -246,14 +246,14 @@ public class SaSession implements Serializable {
* 更新Session从持久库更新刷新一下
*/
public void update() {
SaTokenManager.getSaTokenDao().updateSession(this);
SaManager.getSaTokenDao().updateSession(this);
}
/** 注销Session (从持久库删除) */
public void logout() {
SaTokenManager.getSaTokenDao().deleteSession(this.id);
SaManager.getSaTokenDao().deleteSession(this.id);
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doLogoutSession(id);
SaManager.getSaTokenListener().doLogoutSession(id);
}
/** 当Session上的tokenSign数量为零时注销会话 */
@@ -268,7 +268,7 @@ public class SaSession implements Serializable {
* @return 此Session的剩余存活时间 (单位: 秒)
*/
public long getTimeout() {
return SaTokenManager.getSaTokenDao().getSessionTimeout(this.id);
return SaManager.getSaTokenDao().getSessionTimeout(this.id);
}
/**
@@ -276,7 +276,7 @@ public class SaSession implements Serializable {
* @param timeout 过期时间 (单位: 秒)
*/
public void updateTimeout(long timeout) {
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
SaManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
}
/**
@@ -285,7 +285,7 @@ public class SaSession implements Serializable {
*/
public void updateMinTimeout(long minTimeout) {
if(getTimeout() < minTimeout) {
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
SaManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
}
}
@@ -295,7 +295,7 @@ public class SaSession implements Serializable {
*/
public void updateMaxTimeout(long maxTimeout) {
if(getTimeout() > maxTimeout) {
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
SaManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
}
}

View File

@@ -1,6 +1,6 @@
package cn.dev33.satoken.session;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
/**
* 自定义Session工具类
@@ -22,7 +22,7 @@ public class SaSessionCustomUtil {
* @return sessionId
*/
public static String splicingSessionKey(String sessionId) {
return SaTokenManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
return SaManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
}
/**
@@ -32,7 +32,7 @@ public class SaSessionCustomUtil {
* @return 是否存在
*/
public static boolean isExists(String sessionId) {
return SaTokenManager.getSaTokenDao().getSession(splicingSessionKey(sessionId)) != null;
return SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId)) != null;
}
/**
@@ -43,10 +43,10 @@ public class SaSessionCustomUtil {
* @return SaSession
*/
public static SaSession getSessionById(String sessionId, boolean isCreate) {
SaSession session = SaTokenManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
SaSession session = SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
if (session == null && isCreate) {
session = SaTokenManager.getSaTokenAction().createSession(sessionId);
SaTokenManager.getSaTokenDao().setSession(session, SaTokenManager.getConfig().getTimeout());
session = SaManager.getSaTokenAction().createSession(splicingSessionKey(sessionId));
SaManager.getSaTokenDao().setSession(session, SaManager.getConfig().getTimeout());
}
return session;
}
@@ -67,7 +67,7 @@ public class SaSessionCustomUtil {
* @param sessionId 指定key
*/
public static void deleteSessionById(String sessionId) {
SaTokenManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
SaManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
}
}

View File

@@ -1,6 +1,6 @@
package cn.dev33.satoken.stp;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaTokenConsts;
@@ -97,7 +97,7 @@ public class SaLoginModel {
* @return 对象自身
*/
public SaLoginModel build() {
return build(SaTokenManager.getConfig());
return build(SaManager.getConfig());
}
/**

View File

@@ -1,17 +1,17 @@
package cn.dev33.satoken.stp;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
@@ -23,8 +23,8 @@ import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import cn.dev33.satoken.util.SaTokenInsideUtil;
/**
* sa-token 权限验证,逻辑实现类
@@ -46,7 +46,7 @@ public class StpLogic {
public StpLogic(String loginKey) {
this.loginKey = loginKey;
// 在 SaTokenManager 中记录下此 StpLogic以便根据 LoginKey 进行查找此对象
SaTokenManager.putStpLogic(this);
SaManager.putStpLogic(this);
}
/**
@@ -84,7 +84,7 @@ public class StpLogic {
* @return 生成的tokenValue
*/
public String createTokenValue(Object loginId) {
return SaTokenManager.getSaTokenAction().createToken(loginId, loginKey);
return SaManager.getSaTokenAction().createToken(loginId, loginKey);
}
/**
@@ -95,10 +95,10 @@ public class StpLogic {
public void setTokenValue(String tokenValue, int cookieTimeout){
SaTokenConfig config = getConfig();
// 将token保存到[存储器]里
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
SaStorage storage = SaHolder.getStorage();
// 判断是否配置了token前缀
String tokenPrefix = config.getTokenPrefix();
if(SaTokenInsideUtil.isEmpty(tokenPrefix)) {
if(SaFoxUtil.isEmpty(tokenPrefix)) {
storage.set(splicingKeyJustCreatedSave(), tokenValue);
} else {
// 如果配置了token前缀则拼接上前缀一起写入
@@ -107,7 +107,7 @@ public class StpLogic {
// 注入Cookie
if(config.getIsReadCookie() == true){
SaResponse response = SaTokenManager.getSaTokenContext().getResponse();
SaResponse response = SaHolder.getResponse();
response.addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), cookieTimeout);
}
}
@@ -118,8 +118,8 @@ public class StpLogic {
*/
public String getTokenValue(){
// 0. 获取相应对象
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
SaRequest request = SaTokenManager.getSaTokenContext().getRequest();
SaStorage storage = SaHolder.getStorage();
SaRequest request = SaHolder.getRequest();
SaTokenConfig config = getConfig();
String keyTokenName = getTokenName();
String tokenValue = null;
@@ -143,7 +143,7 @@ public class StpLogic {
// 5. 如果打开了前缀模式
String tokenPrefix = getConfig().getTokenPrefix();
if(SaTokenInsideUtil.isEmpty(tokenPrefix) == false && SaTokenInsideUtil.isEmpty(tokenValue) == false) {
if(SaFoxUtil.isEmpty(tokenPrefix) == false && SaFoxUtil.isEmpty(tokenValue) == false) {
// 如果token以指定的前缀开头, 则裁剪掉它, 否则视为未提供token
if(tokenValue.startsWith(tokenPrefix + SaTokenConsts.TOKEN_CONNECTOR_CHAT)) {
tokenValue = tokenValue.substring(tokenPrefix.length() + SaTokenConsts.TOKEN_CONNECTOR_CHAT.length());
@@ -220,7 +220,7 @@ public class StpLogic {
// ------ 1、获取相应对象
SaTokenConfig config = getConfig();
SaTokenDao dao = SaTokenManager.getSaTokenDao();
SaTokenDao dao = SaManager.getSaTokenDao();
loginModel.build(config);
// ------ 2、生成一个token
@@ -246,7 +246,7 @@ public class StpLogic {
// 3. 清理user-session上的token签名记录
session.removeTokenSign(tokenSign.getValue());
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doReplaced(loginKey, loginId, tokenSign.getValue(), tokenSign.getDevice());
SaManager.getSaTokenListener().doReplaced(loginKey, loginId, tokenSign.getValue(), tokenSign.getDevice());
}
}
}
@@ -277,7 +277,7 @@ public class StpLogic {
setTokenValue(tokenValue, loginModel.getCookieTimeout());
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doLogin(loginKey, loginId, loginModel);
SaManager.getSaTokenListener().doLogin(loginKey, loginId, loginModel);
}
/**
@@ -291,7 +291,7 @@ public class StpLogic {
}
// 如果打开了cookie模式第一步先把cookie清除掉
if(getConfig().getIsReadCookie() == true){
SaTokenManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
SaHolder.getResponse().deleteCookie(getTokenName());
}
logoutByTokenValue(tokenValue);
}
@@ -303,25 +303,28 @@ public class StpLogic {
public void logoutByTokenValue(String tokenValue) {
// 1. 清理掉[token-最后操作时间]
clearLastActivity(tokenValue);
// 2. 清理Token-Session
SaManager.getSaTokenDao().delete(splicingKeyTokenSession(tokenValue));
// 2. 尝试清除token-id键值对 (先从db中获取loginId值如果根本查不到loginId那么无需继续操作 )
// 3. 尝试清除token-id键值对 (先从db中获取loginId值如果根本查不到loginId那么无需继续操作 )
String loginId = getLoginIdNotHandle(tokenValue);
if(loginId == null || NotLoginException.ABNORMAL_LIST.contains(loginId)) {
return;
}
SaTokenManager.getSaTokenDao().delete(splicingKeyTokenValue(tokenValue));
SaManager.getSaTokenDao().delete(splicingKeyTokenValue(tokenValue));
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doLogout(loginKey, loginId, tokenValue);
// 3. 尝试清理账号session上的token签名 (如果为null或已被标记为异常, 那么无需继续执行 )
SaManager.getSaTokenListener().doLogout(loginKey, loginId, tokenValue);
// 4. 尝试清理User-Session上的token签名 (如果为null或已被标记为异常, 那么无需继续执行 )
SaSession session = getSessionByLoginId(loginId, false);
if(session == null) {
return;
}
session.removeTokenSign(tokenValue);
// 4. 尝试注销session
// 5. 尝试注销User-Session
session.logoutByTokenSignCountToZero();
}
@@ -356,11 +359,11 @@ public class StpLogic {
// 2. 清理掉[token-最后操作时间]
clearLastActivity(tokenValue);
// 3. 标记:已被踢下线
SaTokenManager.getSaTokenDao().update(splicingKeyTokenValue(tokenValue), NotLoginException.KICK_OUT);
SaManager.getSaTokenDao().update(splicingKeyTokenValue(tokenValue), NotLoginException.KICK_OUT);
// 4. 清理账号session上的token签名
session.removeTokenSign(tokenValue);
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doLogoutByLoginId(loginKey, loginId, tokenValue, tokenSign.getDevice());
SaManager.getSaTokenListener().doLogoutByLoginId(loginKey, loginId, tokenValue, tokenSign.getDevice());
}
}
// 3. 尝试注销session
@@ -375,10 +378,10 @@ public class StpLogic {
*/
public void disable(Object loginId, long disableTime) {
// 标注为已被封禁
SaTokenManager.getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime);
SaManager.getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime);
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doDisable(loginKey, loginId, disableTime);
SaManager.getSaTokenListener().doDisable(loginKey, loginId, disableTime);
}
/**
@@ -387,7 +390,7 @@ public class StpLogic {
* @return see note
*/
public boolean isDisable(Object loginId) {
return SaTokenManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
return SaManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
}
/**
@@ -396,7 +399,7 @@ public class StpLogic {
* @return see note
*/
public long getDisableTime(Object loginId) {
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyDisable(loginId));
return SaManager.getSaTokenDao().getTimeout(splicingKeyDisable(loginId));
}
/**
@@ -404,10 +407,10 @@ public class StpLogic {
* @param loginId 账号id
*/
public void untieDisable(Object loginId) {
SaTokenManager.getSaTokenDao().delete(splicingKeyDisable(loginId));
SaManager.getSaTokenDao().delete(splicingKeyDisable(loginId));
// $$ 通知监听器
SaTokenManager.getSaTokenListener().doUntieDisable(loginKey, loginId);
SaManager.getSaTokenListener().doUntieDisable(loginKey, loginId);
}
@@ -460,9 +463,10 @@ public class StpLogic {
if(loginId.equals(NotLoginException.KICK_OUT)) {
throw NotLoginException.newInstance(loginKey, NotLoginException.KICK_OUT);
}
// 如果配置了自动续签, 则: 检查是否已经 [临时过期],同时更新[最后操作时间]
// 检查是否已经 [临时过期]
checkActivityTimeout(tokenValue);
// 如果配置了自动续签, 则: 更新[最后操作时间]
if(getConfig().getAutoRenew()) {
checkActivityTimeout(tokenValue);
updateLastActivityToNow(tokenValue);
}
// 至此返回loginId
@@ -564,7 +568,7 @@ public class StpLogic {
* @return loginId
*/
public String getLoginIdNotHandle(String tokenValue) {
return SaTokenManager.getSaTokenDao().get(splicingKeyTokenValue(tokenValue));
return SaManager.getSaTokenDao().get(splicingKeyTokenValue(tokenValue));
}
@@ -577,10 +581,10 @@ public class StpLogic {
* @return session对象
*/
public SaSession getSessionBySessionId(String sessionId, boolean isCreate) {
SaSession session = SaTokenManager.getSaTokenDao().getSession(sessionId);
SaSession session = SaManager.getSaTokenDao().getSession(sessionId);
if(session == null && isCreate) {
session = SaTokenManager.getSaTokenAction().createSession(sessionId);
SaTokenManager.getSaTokenDao().setSession(session, getConfig().getTimeout());
session = SaManager.getSaTokenAction().createSession(sessionId);
SaManager.getSaTokenDao().setSession(session, getConfig().getTimeout());
}
return session;
}
@@ -699,7 +703,7 @@ public class StpLogic {
return;
}
// 将[最后操作时间]标记为当前时间戳
SaTokenManager.getSaTokenDao().set(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout());
SaManager.getSaTokenDao().set(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout());
}
/**
@@ -712,9 +716,9 @@ public class StpLogic {
return;
}
// 删除[最后操作时间]
SaTokenManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
SaManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
// 清除标记
SaTokenManager.getSaTokenContext().getStorage().delete((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
SaHolder.getStorage().delete((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
}
/**
@@ -727,7 +731,7 @@ public class StpLogic {
return;
}
// 如果本次请求已经有了[检查标记], 则立即返回
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
SaStorage storage = SaHolder.getStorage();
if(storage.get(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
return;
}
@@ -764,7 +768,7 @@ public class StpLogic {
if(tokenValue == null || getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
return;
}
SaTokenManager.getSaTokenDao().update(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
SaManager.getSaTokenDao().update(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
}
/**
@@ -784,7 +788,7 @@ public class StpLogic {
* @return token剩余有效时间
*/
public long getTokenTimeout() {
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
return SaManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
}
/**
@@ -793,7 +797,7 @@ public class StpLogic {
* @return token剩余有效时间
*/
public long getTokenTimeoutByLoginId(Object loginId) {
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValueByLoginId(loginId)));
return SaManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValueByLoginId(loginId)));
}
/**
@@ -810,7 +814,7 @@ public class StpLogic {
* @return token剩余有效时间
*/
public long getSessionTimeoutByLoginId(Object loginId) {
return SaTokenManager.getSaTokenDao().getSessionTimeout(splicingKeySession(loginId));
return SaManager.getSaTokenDao().getSessionTimeout(splicingKeySession(loginId));
}
/**
@@ -827,7 +831,7 @@ public class StpLogic {
* @return token剩余有效时间
*/
public long getTokenSessionTimeoutByTokenValue(String tokenValue) {
return SaTokenManager.getSaTokenDao().getSessionTimeout(splicingKeyTokenSession(tokenValue));
return SaManager.getSaTokenDao().getSessionTimeout(splicingKeyTokenSession(tokenValue));
}
/**
@@ -855,7 +859,7 @@ public class StpLogic {
// ------ 开始查询
// 获取相关数据
String keyLastActivityTime = splicingKeyLastActivityTime(tokenValue);
String lastActivityTimeString = SaTokenManager.getSaTokenDao().get(keyLastActivityTime);
String lastActivityTimeString = SaManager.getSaTokenDao().get(keyLastActivityTime);
// 查不到,返回-2
if(lastActivityTimeString == null) {
return SaTokenDao.NOT_VALUE_EXPIRE;
@@ -881,8 +885,9 @@ public class StpLogic {
* @return 是否含有指定角色标识
*/
public boolean hasRole(Object loginId, String role) {
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
return !(roleList == null || roleList.contains(role) == false);
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
return SaManager.getSaTokenAction().hasElement(roleList, role);
// return !(roleList == null || roleList.contains(role) == false);
}
/**
@@ -910,9 +915,9 @@ public class StpLogic {
*/
public void checkRoleAnd(String... roleArray){
Object loginId = getLoginId();
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
for (String role : roleArray) {
if(roleList.contains(role) == false) {
if(SaManager.getSaTokenAction().hasElement(roleList, role) == false) {
throw new NotRoleException(role, this.loginKey);
}
}
@@ -924,9 +929,9 @@ public class StpLogic {
*/
public void checkRoleOr(String... roleArray){
Object loginId = getLoginId();
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
for (String role : roleArray) {
if(roleList.contains(role) == true) {
if(SaManager.getSaTokenAction().hasElement(roleList, role) == true) {
// 有的话提前退出
return;
}
@@ -946,8 +951,9 @@ public class StpLogic {
* @return 是否含有指定权限
*/
public boolean hasPermission(Object loginId, String permission) {
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
return !(permissionList == null || permissionList.contains(permission) == false);
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
return SaManager.getSaTokenAction().hasElement(permissionList, permission);
// return !(permissionList == null || permissionList.contains(permission) == false);
}
/**
@@ -975,9 +981,9 @@ public class StpLogic {
*/
public void checkPermissionAnd(String... permissionArray){
Object loginId = getLoginId();
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
for (String permission : permissionArray) {
if(permissionList.contains(permission) == false) {
if(SaManager.getSaTokenAction().hasElement(permissionList, permission) == false) {
throw new NotPermissionException(permission, this.loginKey);
}
}
@@ -989,9 +995,9 @@ public class StpLogic {
*/
public void checkPermissionOr(String... permissionArray){
Object loginId = getLoginId();
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
for (String permission : permissionArray) {
if(permissionList.contains(permission) == true) {
if(SaManager.getSaTokenAction().hasElement(permissionList, permission) == true) {
// 有的话提前退出
return;
}
@@ -1100,7 +1106,7 @@ public class StpLogic {
* @return token集合
*/
public List<String> searchTokenValue(String keyword, int start, int size) {
return SaTokenManager.getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size);
return SaManager.getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size);
}
/**
@@ -1111,7 +1117,7 @@ public class StpLogic {
* @return sessionId集合
*/
public List<String> searchSessionId(String keyword, int start, int size) {
return SaTokenManager.getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size);
return SaManager.getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size);
}
/**
@@ -1122,7 +1128,7 @@ public class StpLogic {
* @return sessionId集合
*/
public List<String> searchTokenSessionId(String keyword, int start, int size) {
return SaTokenManager.getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size);
return SaManager.getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size);
}
@@ -1205,68 +1211,44 @@ public class StpLogic {
*/
public SaTokenConfig getConfig() {
// 为什么再次代理一层? 为某些极端业务场景下[需要不同StpLogic不同配置]提供便利
return SaTokenManager.getConfig();
return SaManager.getConfig();
}
// =================== 其它方法 ===================
/**
* 根据注解(@SaCheckLogin)鉴权
* @param at 注解对象
*/
public void checkByAnnotation(SaCheckLogin at) {
this.checkLogin();
}
/**
* 根据注解(@SaCheckRole)鉴权
* @param at 注解对象
*/
public void checkByAnnotation(SaCheckRole at) {
String[] roleArray = at.value();
if(at.mode() == SaMode.AND) {
this.checkRoleAnd(roleArray);
} else {
this.checkRoleOr(roleArray);
}
}
/**
* 对一个Method对象进行注解检查注解鉴权内部实现
* @param method Method对象
* 根据注解(@SaCheckPermission)鉴权
* @param at 注解对象
*/
public void checkMethodAnnotation(Method method) {
// ----------- 验证登录
if(method.isAnnotationPresent(SaCheckLogin.class) || method.getDeclaringClass().isAnnotationPresent(SaCheckLogin.class)) {
this.checkLogin();
public void checkByAnnotation(SaCheckPermission at) {
String[] permissionArray = at.value();
if(at.mode() == SaMode.AND) {
this.checkPermissionAnd(permissionArray);
} else {
this.checkPermissionOr(permissionArray);
}
// ----------- 验证角色
// 验证方法上的
SaCheckRole scr = method.getAnnotation(SaCheckRole.class);
if(scr != null) {
String[] roleArray = scr.value();
if(scr.mode() == SaMode.AND) {
this.checkRoleAnd(roleArray);
} else {
this.checkRoleOr(roleArray);
}
}
// 验证类上的
scr = method.getDeclaringClass().getAnnotation(SaCheckRole.class);
if(scr != null) {
String[] roleArray = scr.value();
if(scr.mode() == SaMode.AND) {
this.checkRoleAnd(roleArray);
} else {
this.checkRoleOr(roleArray);
}
}
// ----------- 验证权限
// 验证方法上的
SaCheckPermission scp = method.getAnnotation(SaCheckPermission.class);
if(scp != null) {
String[] permissionArray = scp.value();
if(scp.mode() == SaMode.AND) {
this.checkPermissionAnd(permissionArray);
} else {
this.checkPermissionOr(permissionArray);
}
}
// 验证类上的
scp = method.getDeclaringClass().getAnnotation(SaCheckPermission.class);
if(scp != null) {
String[] permissionArray = scp.value();
if(scp.mode() == SaMode.AND) {
this.checkPermissionAnd(permissionArray);
} else {
this.checkPermissionOr(permissionArray);
}
}
// 验证通过
}
@@ -1277,14 +1259,14 @@ public class StpLogic {
* @param loginId 指定loginId
*/
public void switchTo(Object loginId) {
SaTokenManager.getSaTokenContext().getStorage().set(splicingKeySwitch(), loginId);
SaHolder.getStorage().set(splicingKeySwitch(), loginId);
}
/**
* 结束临时切换身份
*/
public void endSwitch() {
SaTokenManager.getSaTokenContext().getStorage().delete(splicingKeySwitch());
SaHolder.getStorage().delete(splicingKeySwitch());
}
/**
@@ -1292,7 +1274,7 @@ public class StpLogic {
* @return 是否正处于[身份临时切换]中
*/
public boolean isSwitch() {
return SaTokenManager.getSaTokenContext().getStorage().get(splicingKeySwitch()) != null;
return SaHolder.getStorage().get(splicingKeySwitch()) != null;
}
/**
@@ -1300,7 +1282,7 @@ public class StpLogic {
* @return 返回[身份临时切换]的loginId
*/
public Object getSwitchLoginId() {
return SaTokenManager.getSaTokenContext().getStorage().get(splicingKeySwitch());
return SaHolder.getStorage().get(splicingKeySwitch());
}
/**

View File

@@ -10,13 +10,17 @@ import cn.dev33.satoken.session.SaSession;
* @author kong
*/
public class StpUtil {
/**
* 账号体系标识
*/
public static final String KEY = "login";
/**
* 底层的 StpLogic 对象
*/
public static StpLogic stpLogic = new StpLogic("login");
public static StpLogic stpLogic = new StpLogic(KEY);
/**
* 获取当前StpLogin的loginKey
* @return 当前StpLogin的loginKey

View File

@@ -7,14 +7,15 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
/**
* sa-token 内部代码工具类
* Sa-Token 内部工具类
*
* @author kong
*
*/
public class SaTokenInsideUtil {
public class SaFoxUtil {
/**
* 打印 sa-token 版本字符画
@@ -129,4 +130,21 @@ public class SaTokenInsideUtil {
return list2;
}
/**
* 字符串模糊匹配
* <p>example:
* <p> user* user-add -- true
* <p> user* art-add -- false
* @param patt 表达式
* @param str 待匹配的字符串
* @return 是否可以匹配
*/
public static boolean vagueMatch(String patt, String str) {
// 如果表达式不带有*则只需简单equals即可 (速度提升200倍)
if(patt.indexOf("*") == -1) {
return patt.equals(str);
}
return Pattern.matches(patt.replaceAll("\\*", ".*"), str);
}
}

View File

@@ -13,7 +13,7 @@ public class SaTokenConsts {
/**
* sa-token 当前版本号
*/
public static final String VERSION_NO = "v1.17.0";
public static final String VERSION_NO = "v1.19.0";
/**
* sa-token 开源地址

View File

@@ -1,50 +0,0 @@
package com.pj.satoken;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
/**
* [Sa-Token 权限认证] 配置类
* @author kong
*
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/**
* 注册sa-token的拦截器打开注解式鉴权功能
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册注解拦截器
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**").excludePathPatterns("");
}
// /**
// * 注册 [sa-token全局过滤器]
// */
// @Bean
// public SaServletFilter getSaReactorFilter() {
// return new SaServletFilter()
// // 指定 [拦截路由]
// .addInclude("/**")
// // 指定 [放行路由]
// .addExclude("/favicon.ico")
// // 指定[认证函数]: 每次请求执行
// .setAuth(r -> {
// System.out.println("---------- sa全局认证");
// SaRouterUtil.match("/test/test", () -> StpUtil.checkLogin());
// })
// // 指定[异常处理函数]:每次[认证函数]发生异常时执行此函数
// .setError(e -> {
// System.out.println("---------- sa全局异常 ");
// return AjaxJson.getError(e.getMessage());
// })
// ;
// }
}

View File

@@ -16,7 +16,7 @@
<!-- 定义sa-token版本号 -->
<properties>
<sa-token-version>1.17.0</sa-token-version>
<sa-token-version>1.19.0</sa-token-version>
</properties>
<dependencies>

View File

@@ -3,14 +3,14 @@ package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
@SpringBootApplication
public class SaTokenJwtDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenJwtDemoApplication.class, args);
System.out.println("\n启动成功sa-token配置如下" + SaTokenManager.getConfig());
System.out.println("\n启动成功sa-token配置如下" + SaManager.getConfig());
}
}

View File

@@ -4,7 +4,7 @@ import java.util.Date;
import org.springframework.stereotype.Component;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.dao.SaTokenDao;
@@ -124,13 +124,13 @@ public class SaTokenJwtUtil {
@Override
public void setLoginId(Object loginId, SaLoginModel loginModel) {
// ------ 1获取相应对象
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
SaStorage storage = SaManager.getSaTokenContext().getStorage();
SaTokenConfig config = getConfig();
// ------ 2生成一个token
String tokenValue = createTokenValue(loginId);
storage.set(splicingKeyJustCreatedSave(), tokenValue); // 将token保存到本次request里
if(config.getIsReadCookie() == true){ // cookie注入
SaTokenManager.getSaTokenContext().getResponse().addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), (int)config.getTimeout());
SaManager.getSaTokenContext().getResponse().addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), (int)config.getTimeout());
}
}
@@ -154,7 +154,7 @@ public class SaTokenJwtUtil {
}
// 如果打开了cookie模式把cookie清除掉
if(getConfig().getIsReadCookie() == true){
SaTokenManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
SaManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
}
}

View File

@@ -71,8 +71,10 @@ public class TestJwtController {
// 测试 浏览器访问 http://localhost:8081/test/test
@RequestMapping("test")
public AjaxJson test() {
StpUtil.getTokenSession().logout();
StpUtil.logoutByLoginId(10001);
System.out.println();
System.out.println("--------------进入请求--------------");
StpUtil.setLoginId(10001);
System.out.println(StpUtil.getTokenInfo().getTokenValue());
return AjaxJson.getSuccess();
}

View File

@@ -0,0 +1,68 @@
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-demo-quick-login</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- SpringBoot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<!-- 定义sa-token版本号 -->
<properties>
<sa-token-version>1.19.0</sa-token-version>
</properties>
<dependencies>
<!-- springboot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- quick-login -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-quick-login</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- @ConfigurationProperties -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 热更新插件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,52 @@
package com.pj;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import cn.dev33.satoken.quick.SaQuickManager;
/**
* springboot启动之后
* @author kong
*
*/
@Component
public class SaQuicikStartup implements CommandLineRunner {
@Value("${spring.application.name:sa-quick}")
private String applicationName;
@Value("${server.port:8080}")
private String port;
@Value("${server.servlet.context-path:}")
private String path;
// @Value("${spring.profiles.active:}")
// private String active;
@Override
public void run(String... args) throws Exception {
String str = "\n------------- " + applicationName + " 启动成功 (" + getNow() + ") -------------\n" +
" - home: " + "http://localhost:" + port + path + "\n" +
" - name: " + SaQuickManager.getConfig().getName() + "\n"+
" - pwd : " + SaQuickManager.getConfig().getPwd() + "\n";
System.out.println(str);
}
/**
* 返回系统当前时间的YYYY-MM-dd hh:mm:ss 字符串格式
*/
private static String getNow(){
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}

View File

@@ -0,0 +1,13 @@
package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SaTokenQuickDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenQuickDemoApplication.class, args);
}
}

View File

@@ -0,0 +1,27 @@
package com.pj.test;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.util.SaTokenConsts;
/**
* 测试专用Controller
* @author kong
*
*/
@RestController
public class TestController {
// 浏览器访问测试: http://localhost:8081
@RequestMapping({"/"})
public String login(String username, String password) {
String str = "<br />"
// + "<h1 style='text-align: center;'>Welcome to the system</h1>"
+ "<h1 style='text-align: center;'>资源页 (登录后才可进入本页面) </h1>"
+ "<hr/>"
+ "<p style='text-align: center;'> Sa-Token " + SaTokenConsts.VERSION_NO + " </p>";
return str;
}
}

View File

@@ -0,0 +1,27 @@
# 端口
server:
port: 8081
# Sa-Token-Quick-Login 配置
sa:
# 登录账号
name: sa
# 登录密码
pwd: 123456
# 是否自动随机生成账号密码 (此项为true时, name与pwd失效)
auto: false
# 是否开启全局认证(关闭后将不再强行拦截)
auth: true
# 登录页标题
title: Sa-Token 登录
# 是否显示底部版权信息
copr: true
# 将本地磁盘的某个路径作为静态资源开放
# dir: file:E:\static
# 静态文件路径映射
spring:
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/, ${sa.dir:}

View File

@@ -16,7 +16,7 @@
<!-- 定义sa-token版本号 -->
<properties>
<sa-token-version>1.17.0</sa-token-version>
<sa-token-version>1.19.0</sa-token-version>
</properties>
<dependencies>

View File

@@ -3,7 +3,7 @@ package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
/**
* sa-token整合SpringBoot 示例
@@ -15,7 +15,7 @@ public class SaTokenDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenDemoApplication.class, args);
System.out.println("\n启动成功sa-token配置如下" + SaTokenManager.getConfig());
System.out.println("\n启动成功sa-token配置如下" + SaManager.getConfig());
}
}

View File

@@ -0,0 +1,72 @@
package com.pj.satoken;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
/**
* [Sa-Token 权限认证] 配置类
* @author kong
*
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/**
* 注册sa-token的拦截器打开注解式鉴权功能
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册注解拦截器
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**").excludePathPatterns("");
}
/**
* 注册 [sa-token全局过滤器]
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
// 指定 [拦截路由] 与 [放行路由]
.addInclude("/**").addExclude("/favicon.ico")
// 认证函数: 每次请求执行
.setAuth(r -> {
// System.out.println("---------- sa全局认证");
// SaRouterUtil.match("/test/test", () -> new Object());
})
// 异常处理函数:每次认证函数发生异常时执行此函数
.setError(e -> {
System.out.println("---------- sa全局异常 ");
return AjaxJson.getError(e.getMessage());
})
// 前置函数:在每次认证函数之前执行
.setBeforeAuth(r -> {
// ---------- 设置一些安全响应头 ----------
SaHolder.getResponse()
// 服务器名称
.setServer("sa-server")
// 是否可以在iframe显示视图 DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
.setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否启用浏览器默认XSS防护 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时停止渲染页面
.setHeader("X-Frame-Options", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
;
})
;
}
}

View File

@@ -241,8 +241,7 @@ public class TestController {
@RequestMapping("test")
public AjaxJson test() {
System.out.println("进来了");
StpUtil.disable(10001, 10002);
StpUtil.untieDisable(10001);
System.out.println(StpUtil.getTokenInfo());
return AjaxJson.getSuccess("访问成功");
}

View File

@@ -20,7 +20,6 @@ spring:
# 是否输出操作日志
is-log: false
# redis配置
redis:
# Redis数据库索引默认为0
@@ -44,4 +43,7 @@ spring:
# 连接池中的最小空闲连接
min-idle: 0

View File

@@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.idea/
.factorypath

View File

@@ -16,7 +16,7 @@
<!-- 定义sa-token版本号 -->
<properties>
<sa-token-version>1.17.0</sa-token-version>
<sa-token-version>1.19.0</sa-token-version>
</properties>
<dependencies>

View File

@@ -14,7 +14,7 @@ package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.SaManager;
/**
* sa-token整合webflux 示例
@@ -26,7 +26,7 @@ public class SaTokenWebfluxDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenWebfluxDemoApplication.class, args);
System.out.println("\n启动成功sa-token配置如下" + SaTokenManager.getConfig());
System.out.println("\n启动成功sa-token配置如下" + SaManager.getConfig());
}
}

View File

@@ -1,7 +1,7 @@
<p align="center">
<img alt="logo" src="https://gitee.com/dromara/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.17.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.19.0</h1>
<h4 align="center">这可能是史上功能最全的 Java 权限认证框架!</h4>
<h4 align="center">
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
@@ -91,6 +91,7 @@ StpUtil.checkLogin();
当你受够Shiro、Security等框架的三拜九叩之后你就会明白相对于这些传统老牌框架sa-token的API设计是多么的清爽
权限认证示例 (只有具有`user:add`权限的会话才可以进入请求)
``` java
@SaCheckPermission("user:add")
@RequestMapping("/user/insert")
@@ -150,6 +151,7 @@ sa-token秉承着开放的思想欢迎大家为框架添砖加瓦
[**[ jthink]** 一个基于springboot+sa-token+thymeleaf的博客系统](https://gitee.com/wtsoftware/jthink)
[**[ dcy-fast]** 一个基于springboot+sa-token+mybatis-plus的后台管理系统前端vue-element-admin并且内置代码生成器](https://gitee.com/dcy421/dcy-fast)
如果您的项目使用了sa-token欢迎提交pr

View File

@@ -7,8 +7,8 @@
- [在WebFlux环境集成](/start/webflux-example)
- **基础**
- [登录](/use/login-auth)
- [权限](/use/jur-auth)
- [登录](/use/login-auth)
- [权限](/use/jur-auth)
- [Session会话](/use/session)
- [踢人下线](/use/kick)
- [注解式鉴权](/use/at-check)
@@ -33,6 +33,10 @@
- [单点登录](/senior/sso)
- [多账号验证](/use/many-account)
- **插件**
- [AOP注解鉴权](/plugin/aop-at)
- [Quick-Login快速登录插件](/plugin/quick-login)
- **其它**
- [常见问题](/more/common-questions)
- [更新日志](/more/update-log)
@@ -45,6 +49,7 @@
- [Session模型详解](/fun/session-model)
- [TokenInfo参数详解](/fun/token-info)
- [框架源码所有技术栈](/fun/tech-stack)
<!-- - [Web开发常见漏洞防护](/fun/web-loophole) -->
<!-- - [Sa-Token大事记](/fun/timeline) -->

View File

@@ -0,0 +1,112 @@
# Web开发常见漏洞防护
本章介绍web开发时常见漏洞的防护方法
### 点击劫持
简而言之,点击劫持就是攻击者会自己搭建一个网页,这个网页分为两层:
- 上层是被iframe导入的被攻击网站具有一些敏感性操作比如转账、点赞等按钮这一层会完全透明
- 下层是攻击者自己精心制作的网页,它会准备一个按钮诱导你进行点击(比如点击领取红包等),当你点击这个按钮时,响应你的将不会是这个按钮,而是上层的转账页面,在不知情的情况下造成财产损失
详情介绍参考:[https://blog.csdn.net/qq_32523587/article/details/79613768](https://blog.csdn.net/qq_32523587/article/details/79613768)
防范点击劫持的最有效做法就是增加响应头:`X-Frame-Options: DENY`, 告诉浏览器我们的网站不可以通过 iframe 进行展示(浏览器收到此响应头的指示之后,会拒绝渲染页面),
从根本上杜绝了点击劫持发生的可能,在 [全局过滤器](/use/global-filter) 章节的示例中,我们已经展示了如何在过滤器中增加安全响应头
响应头`X-Frame-Options`有三个取值:
- `DENY`: 任何时候都不可以通过 iframe 展示视图
- `SAMEORIGIN`: 在同域下可以通过 iframe 展示视图
- `ALLOW-FROM uri`: 指定地址来源的访问下可以通过 iframe 展示视图
除了后端的响应头,我们还可以在前端使用如下方式进行判断:
``` js
// 判断当前页面是否在顶层视口打开
if(top != window) {
// 跳入一个安全页面比如404页
location.href="xxx";
}
```
除了跳转页面你还可以用其它方法防御点击劫持比如加载一个全局遮罩来隔离用户的点击操作或者在非顶层窗口下拒绝提交token使用户保持未登录状态
### XSS攻击
XSS跨站脚本攻击就是指攻击者在一段正常的内容中嵌入恶意脚本使得访问网页的用户自动运行一些破坏性的代码
例如一个论坛具有发帖功能,攻击者在发帖时故意插入一段如下内容:
``` java
<img src="xxx" onerror="alert('xss攻击')" />
```
如果论坛服务端没有对此进行任何防护,那么用户每次访问这个帖子的时候都会被强制弹窗,
事实上真正的`XSS攻击`绝不只是弹窗骚扰一下那么简单它可以完成窃取Cookie自动转账等破坏性操作
防范XSS攻击
1. 首先安全响应头给安排上:`X-Frame-Options: 1; mode=block`, 这是浏览器默认提供的XSS防护机制
2. 有条件的情况下尽量使用前后台分离架构传统服务端渲染视图时几乎每一个变量都可能成为XSS注入点而前后台分离下一般只有富文本渲染才会有机会XSS注入
3. 对所有的用户输入必须XSS过滤特别是字符串型参数
4. 可以使用一些自动扫描工具寻找潜在的 XSS 漏洞
### CSRF攻击
CSRF跨站请求伪造又称 XSRF攻击流程如下
1. 用户登陆站点`a.com`身份令牌被写入Cookie中
2. 攻击者搭建站点`b.com`,引诱用户访问
3. 用户访问`b.com`时自动执行了攻击者准备的js代码调用`a.com`的转账接口
4. 用户在不知情的情况下,造成了财产损失
仅仅访问一个不安全的站点就让我们造成了财产损失事实上真正的CSRF攻击并没有这么简单挡在攻击者第一道门槛便是`CORS同源策略`
同源策略限制了js在`b.com`中只能操作`b.com`的数据(`Cookie`、`localStorage`、`DOM`等),而无法直接操作`a.com`的数据。
这就导致一个结果:虽然在`b.com`可以调用`a.com`的转账接口,但是却无法携带用户储存在`a.com`的授权Cookie对于`a.com`来讲,即使收到了浏览器发来的请求,
也因为请求中没有携带token令牌而无法识别调用者具体是谁只能将其视为一次无效调用。
但是,请注意!这个小小的限制,虽然为用户提供了安全保护,却也为我们开发者造成了不小的困扰,特别是在前后端分离架构下,我们经常会遇到这个错误:
![https://oss.dev33.cn/sa-token/doc/kuayu.png](https://oss.dev33.cn/sa-token/doc/kuayu.png)
这就是导致无数前端后端互相撕逼的 —— 跨域!
浏览器在检测到你身处`b.com`却想要调用`a.com`的接口时,会率先发送一个`OPTIONS`预检请求,目的是为了询问`a.com`是否同意`b.com`发起的请求,
在默认情况下,`a.com`收到一个陌生的第三方网站发来的请求,做出的回应肯定是:`不允许`, 浏览器收到回应就识相的关闭了请求,跨域请求失败
但是,有些开发者为了省事,直接设置了响应头: `Access-Control-Allow-Origin: *`,允许任何第三方网站的请求,这就给`CSRF攻击`留下了可乘之机
假设我们设置了只允许指定的网站跨域请求就万事大吉了吗并没有攻击者仍可以通过抓包等手段得到我们的转账url
在`b.com`里,通过`open(url)`直接打开一个新的窗口调用转账接口,由于是属于打开新页面,浏览器连`OPTIONS`预检请求都不会发送,而是直接调用接口成功
此招无解吗?并不。由于它是属于打开新页面,这就导致调用接口时只能发送`get请求`,我们在设计接口时只需要遵守一个准则:`敏感接口一律post禁止get调用`即可。
究其原因,导致`CSRF攻击`频频发生的原因是什么?是我们在跨域请求时,浏览器总是“自作聪明”的自动提交主站`Cookie`
在浏览器的不断更新中Cookie的跨域规则变得愈发复杂新手开发者及其容易绕的晕头转向而同时`w3c`对`Cookie`规范的各种修修补补又总是解决一个问题的同时暴露出其他的N多问题
既然Cookie机制如此难以驾驭我们何不果断的放弃Cookie机制改用`localStorage`机制存储会话token这种方式轻松避免了`自动提交`带来的各种安全问题。
事实上,`localStorage存储` + `header请求头提交`也是前后台分离趋势下的常见会话处理方案
篇幅有限,我们总结一下防范`CSRF攻击`要点
**在Cookie模式下**
1. 仅靠`CORS同源策略`无法彻底防范`CSRF攻击`,我们必须在后台建立`第三方域名白名单`,只有在白名单中的第三方域名才可以跨域调用我们的接口
2. 涉及到数据增删改类型的接口,必须是`post`模式(或其它),严禁`get`模式,查询接口可以`get`
3. 敏感操作增加验证码或者二次验证密码,减小被攻击的概率
**在 localStorage存储 + header请求头提交 模式下**
1. 在配置文件中,配置`is-read-cookie: false`关闭Cookie模式防止Sa-Token在登录时注入Cookie
2. 同上,敏感操作增加验证码或者二次验证密码,减小被攻击的概率
有关CSRF攻防讲解的比较通透的一篇文章[https://juejin.cn/post/6844903689702866952](https://juejin.cn/post/6844903689702866952)
### Token泄露
Token泄露一般发生在客户端比如用户连接了不安全的WiFi导致通讯被监听虽然此情形下token泄露的责任在于用户但是我们还是有必要采取一定的措施使其损失降到最低
1. 有条件上https的话一律https
2. token有效期一定不能设置为永久而且要尽量的短but为了不影响用户体验又不能设置特别的短so: 7-30天是个比较合适的范围
3. 对敏感操作接口,增加密码二次校验(或手机验证码等)
4. 用户更改密码后使其历史会话直接过期
5. 有条件的情况下后台管理增加踢人下线功能对已经泄露token的账号可以及时清理下线
<br><br>
更多类型漏洞连载中.... 欢迎提交pr

View File

@@ -15,12 +15,14 @@
<a href="/">
<div class="logo-box">
<img src="logo.png" title="logo" />
<h1 class="logo-text">sa-token</h1>
<h1 class="logo-text">Sa-Token</h1>
</div>
</a>
<nav>
<select onchange="location.href=this.value">
<option value="http://sa-token.dev33.cn/doc/index.html">最新版</option>
<option value="http://sa-token.dev33.cn/v/v1.18.0/doc/index.html">v1.18.0</option>
<option value="http://sa-token.dev33.cn/v/v1.17.0/doc/index.html">v1.17.0</option>
<option value="http://sa-token.dev33.cn/v/v1.16.0/doc/index.html">v1.16.0</option>
<option value="http://sa-token.dev33.cn/v/v1.15.0/doc/index.html">v1.15.0</option>
<option value="http://sa-token.dev33.cn/v/v1.14.0/doc/index.html">v1.14.0</option>
@@ -47,7 +49,7 @@
</div>
<script>
var name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
name += '<b style="font-size: 28px; vertical-align: middle;">sa-token</b> <sub>v1.17.0</sub>'
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v1.19.0</sub>'
window.$docsify = {
name: name, // 名字
repo: 'https://github.com/dromara/sa-token', // github地址

View File

@@ -82,7 +82,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
}
/* 代码行号盒子样式 */
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px;}
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px; user-select: none;}
.code-line-box {padding: calc(1.5em + 1px) 0px !important; padding-bottom: calc(1.5em + 20px) !important; margin: 0px !important;}
.code-line-box {line-height: inherit !important; background-color: #111; color: #aaa;font-weight: 400;font-size: 0.85em;text-align: center;}
.code-line-box {font-family: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace;}

View File

@@ -7,6 +7,36 @@
<table class="gzh-table" style="text-align: center;">
<tr>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzk0MjE5MTk5Mw==&mid=2247485576&idx=1&sn=d955d60ab193d895fbd15c37bedebcb8&send_time="/>
<b>Github导航站</b>
<span>分享好玩有趣、新奇、实用的开源项目 </span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzI1MTA3Mzk4Mg==&mid=2651026326&idx=1&sn=3244e18a9a799cd8e0ec375c6c730670&send_time="/>
<b>Java爱好者</b>
<span>分享Java开发编程资源和Java技术文章 </span>
</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzIxODQxMjc0MA==&mid=2247511029&idx=1&sn=42fbb1b8180dc2c995429dabc6f97500&send_time="/>
<b>IT大咖说</b>
<span>大咖干货,不再错过。 </span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzIxNjA5MTM2MA==&mid=2652444329&idx=1&sn=2a040e87f49a977a116c90e1107a9fdc&send_time="/>
<b>Java编程</b>
<span>专注Java技术分享Java基础知识/数据结构/算法</span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzA4MDMyODg4OQ==&mid=2649482871&idx=2&sn=b376585faaf814d9072af539efda68fe&send_time="/>
<b>大侠学JAVA</b>
<span>道阻且长行则将至专注分享JAVA领域的干货</span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzg2MDIxNjAzNg==&mid=2247485810&idx=1&sn=afd46d5924afbc1030a87b5d56265fdf&send_time="/>
<b>Java大厂面试官</b>
@@ -17,9 +47,6 @@
<b>程序员大神</b>
<span>有一个在程序员圈混了10年的老程序员, 分享程序员相关的精选内容教程</span>
</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>

View File

@@ -1,5 +1,25 @@
# 更新日志
### 2021-5-10 @v1.19.0
- 新增注解鉴权新增定制loginKey功能 **[重要]**
- 重构:重构目录结构,抽离`plugin`模块 **[重要]**
- 新增:新增 `sa-token-quick-login` 插件,零代码集成登录功能 **[重要]**
- 优化:所有函数式接口增加`@FunctionalInterface`注解,感谢群友`@MrXionGe`提供的建议
- 优化:文档优化...
### 2021-4-24 @v1.18.0
- 新增:新增权限通配符功能,灵活设置权限 **[重要]**
- 修复:修复自动续签处的逻辑错误
- 新增新增Web开发常见漏洞防护建议
- 修复:修复`SaRequest`中缺少`getMethod()`的bug
- 修复:修复自动续签时的逻辑错误,感谢群成员`@N`的建议
- 新增:全局过滤器新增 `beforAuth` 前置函数
- 修复修复在带有上下文的项目中无法正确获取请求路径的bug感谢群成员`@dlwlrma`提供的建议
- 新增:新增`SaHolder`上下文持有类,可方便的在上下文中读写数据
- 重构:`SaTokenManager` -> `SaManager`
- 重构:`SaTokenInsideUtil` -> `SaFoxUtil`
### 2021-4-17 @v1.17.0
- 修复在WebFlux环境中引入Redis集成包无法启动的问题

View File

@@ -0,0 +1,30 @@
# AOP注解鉴权
---
在 [注解式鉴权](/use/at-check) 章节,我们非常轻松的实现了注解鉴权,
但是默认的拦截器模式却有一个缺点,那就是无法在`Controller层`以外的代码使用进行校验
因此Sa-Token提供AOP插件你只需在`pom.xml`里添加如下依赖,便可以在任意层级使用注解鉴权
``` xml
<!-- sa-token整合SpringAOP实现注解鉴权 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-aop</artifactId>
<version>1.19.0</version>
</dependency>
```
#### 注意点:
- 使用拦截器模式,只能把注解写在`Controller层`使用AOP模式可以将注解写在任意层级 <br>
- **拦截器模式和AOP模式不可同时集成**,否则会在`Controller层`发生一个注解校验两次的bug

View File

@@ -0,0 +1,225 @@
# Sa-Token-Quick-Login 快速登录认证
---
### 解决什么问题
Sa-Token-Quick-Login 可以为一个系统快速的、零代码 注入一个登录页面
试想一下,假如我们开发了一个非常简单的小系统,比如说:服务器性能监控页面,
我们将它部署在服务器上,通过访问这个页面,我们可以随时了解服务器性能信息,非常方便
然而,这个页面方便我们的同时,也方便了一些不法的攻击者,由于这个页面毫无防护的暴露在公网中,任何一台安装了浏览器的电脑都可以随时访问它!
为此,我们必须给这个系统加上一个登录认证,只有知晓了后台密码的人员才可以进行访问
细细想来,完成这个功能你需要:
1. 编写前端登录页面,手写各种表单样式
2. 寻找合适的ajax类库`jQuery``Axios`?还是直接前后台不分离?
3. 寻找合适的模板引擎,比如`jsp``Thymeleaf``FreeMarker``Velocity`……选哪个呢?
4. 处理后台各种拦截认证逻辑,前后台接口对接
5. 你可能还会遇到令人头痛欲裂的模板引擎中`ContextPath`处理
6. ……
你马上就会发现,写个监控页你一下午就可以搞定,然而这个登录页你却可能需要花上两三天的时间,这是一笔及其不划算的时间浪费
那么现在你可能就会有个疑问,难道就没有什么方法给我的小项目快速增加一个登录功能吗?
Sa-Token-Quick-Login便是为了解决这个问题
### 适用场景
Sa-Token-Quick-Login 旨在用最小的成本为项目增加一个登录认证功能
- **简单**:只需要引入一个依赖便可为系统注入登录功能,快速、简单、零代码!
- **不可定制**由于登录页面不可定制所以Sa-Token-Quick-Login非常不适合普通项目的登录认证模块STQL也无意去解决所有项目的登录认证模块
Sa-Token-Quick-Login的定位是这样的场景你的项目需要一个登录认证功能、这个认证页面可以不华丽、可以烂但是一定要有同时你又不想花费太多的时间浪费在登录页面上
那么你便可以尝试一下`Sa-Token-Quick-Login`
### 集成步骤
首先我们需要创建一个SpringBoot的demo项目比如`sa-token-demo-quick-login`
##### 1、添加pom依赖
``` xml
<!-- Sa-Token-Quick-Login 插件 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-quick-login</artifactId>
<version>1.19.0</version>
</dependency>
```
##### 2、启动类
``` java
@SpringBootApplication
public class SaTokenQuickDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenQuickDemoApplication.class, args);
System.out.println("\n------ 启动成功 ------");
System.out.println("name: " + SaQuickManager.getConfig().getName());
System.out.println("pwd: " + SaQuickManager.getConfig().getPwd());
}
}
```
##### 3、新建测试Controller
``` java
/**
* 测试专用Controller
*/
@RestController
public class TestController {
// 浏览器访问测试: http://localhost:8081
@RequestMapping({"/", "/index"})
public String login(String username, String password) {
String str = "<br />"
+ "<h1 style='text-align: center;'>资源页 (登录后才可进入本页面) </h1>"
+ "<hr/>"
+ "<p style='text-align: center;'> Sa-Token " + SaTokenConsts.VERSION_NO + " </p>";
return str;
}
}
```
### 测试访问
启动项目,使用浏览器访问:`http://localhost:8081`,首次访问时,由于处于未登录状态,会被强制进入登录页面
![登录](https://oss.dev33.cn/sa-token/doc/sa-quick-login.png 's-w')
使用默认账号:`sa / 123456`进行登录,会看到资源页面
![登录](https://oss.dev33.cn/sa-token/doc/sa-quick-login-index.png 's-w')
### 可配置信息
你可以在yml中添加如下配置 (所有配置都是可选的)
``` java
# Sa-Token-Quick-Login 配置
sa:
# 登录账号
name: sa
# 登录密码
pwd: 123456
# 是否自动随机生成账号密码 (此项为true时, name与pwd失效)
auto: false
# 是否开启全局认证(关闭后将不再强行拦截)
auth: true
# 登录页标题
title: Sa-Token 登录
# 是否显示底部版权信息
copr: true
```
<br>
**注:**示例源码在`/sa-token-demo/sa-token-demo-quick-login`目录下,可结合源码查看学习
### 使用独立jar包运行
使用`sa-token-quick-login`只需引入一个依赖即可为系统注入登录模块现在我们更进一步将这个项目打成一个独立的jar包
通过这个jar包我们可以方便的部署任意静态网站做到真正的零编码注入登录功能。
##### 打包步骤
首先放上懒人链接:[sa-quick-dist.jar](https://gitee.com/dromara/sa-token/attach_files/695353/download) 不想手动操作的同学可以直接点此链接下载打包后的jar文件
1、首先将 `sa-token-demo-quick-login` 模块添加到顶级父模块的`<modules>`节点中
``` xml
<!-- 所有模块 -->
<modules>
<module>sa-token-core</module>
<module>sa-token-starter</module>
<module>sa-token-plugin</module>
<module>sa-token-demo\sa-token-demo-quick-login</module>
</modules>
```
2、在项目根目录进入cmd执行打包命令
``` cmd
mvn clean package
```
3、进入`\sa-token-demo\sa-token-demo-quick-login\target` 文件夹找到打包好的jar文件
``` cmd
sa-token-demo-quick-login-0.0.1-SNAPSHOT.jar
```
4、我们将其重命名为`sa-quick-dist.jar`现在这个jar包就是我们的最终程序我们在这个`\target`目录直接进入cmd执行如下命令启动jar包
``` cmd
java -jar sa-quick-dist.jar
```
5、测试访问根据控制台输出提示我们使用浏览器访问测试: `http://localhost:8080`
![sa-quick-start](https://oss.dev33.cn/sa-token/doc/sa-quick-start.png 's-w')
如果可以进入登录界面,则代表打包运行成功 <br>
当然仅仅运行成功还不够下面我们演示一下如何使用这个jar包进行静态网站部署
### 所有功能示例
##### Case 1. 指定静态资源路径
``` cmd
java -jar sa-quick-dist.jar --sa.dir file:E:\www
```
使用dir参数指定`E:\www`目录作为资源目录进行部署 (现在我们可以通过浏览器访问`E:\www`目录下的文件了!)
##### Case 2. 指定登录名与密码
``` cmd
java -jar sa-quick-dist.jar --sa.name=zhang --sa.pwd=zhang123
```
现在,默认的账号`sa/123456`将被废弃,而是使用`zhang/zhang123`进行账号校验
##### Case 3. 指定其自动生成账号密码
``` cmd
java -jar sa-quick-dist.jar --sa.auto=true
```
每次启动时随机生成账号密码(会在启动成功时打印到控制台上)
##### Case 4. 指定登录页的标题
``` cmd
java -jar sa-quick-dist.jar --sa.title="XXX 系统登录"
```
##### Case 5. 关闭账号校验,仅作为静态资源部署使用
``` cmd
java -jar sa-quick-dist.jar --sa.auth=false
```
##### Case 6. 指定启动端口默认8080
``` cmd
java -jar sa-quick-dist.jar --server.port=80
```
注:所有参数可组合使用
### 使用SpringBoot默认资源路径
SpringBoot默认开放了一些路径作为资源目录比如`classpath:/static/`
怎么使用呢我们只需要在jar包同目录创建一个`\static`文件夹将静态资源文件复制到此目录下然后启动jar包即可访问
同时我们还可以在jar包同目录创建yml配置文件来覆盖jar包内的yml配置如下图所示
![sa-quick-case.png](https://oss.dev33.cn/sa-token/doc/sa-quick-case.png 's-w')
例如如上目录中`/static`中有一个`1.jpg`文件我们启动jar包后访问`http://localhost:8080/1.jpg`即可查看到此文件这是Springboot自带的功能在此不再赘述

View File

@@ -3,27 +3,29 @@
------
## Maven依赖
在项目中直接通过 `pom.xml` `sa-token` 的依赖即可:
在项目中直接通过 `pom.xml` `sa-token` 的依赖即可(四选一)
<!------------------------------ tabs:start ------------------------------>
<!-- tab:SpringMVC环境 ServletAPI -->
如果你使用的框架基于 ServletAPI 构建( `SpringMVC``SpringBoot``Zuul`等 ),请引入此包
``` xml
<!-- sa-token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</dependency>
```
<!-- tab:WebFlux环境 Reactor -->
注:此依赖适合在 Reactor模式 的web框架中导入例如`Netty`、`WebFlux`等),如果您的项目基于 ServletAPI (`SpringMVC`、`SpringBoot`等),请以前者为准
注:如果你使用的框架基于 Reactor 模型构建(`Netty`、`WebFlux`、`Soul`、`SC Gateway`等,请引入此包
``` xml
<!-- sa-token 权限认证Reactor响应式集成, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</dependency>
```
@@ -34,7 +36,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-servlet</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</dependency>
```
@@ -45,7 +47,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</dependency>
```
<!---------------------------- tabs:end ------------------------------>
@@ -56,19 +58,19 @@
<!-- tabs:start -->
<!-- tab:SpringMVC环境 ServletAPI -->
``` xml
implementation 'cn.dev33:sa-token-spring-boot-starter:1.17.0'
implementation 'cn.dev33:sa-token-spring-boot-starter:1.19.0'
```
<!-- tab:WebFlux环境 Reactor -->
``` xml
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:1.17.0'
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:1.19.0'
```
<!-- tab:Servlet容器环境 -->
``` xml
implementation 'cn.dev33:sa-token-servlet:1.17.0'
implementation 'cn.dev33:sa-token-servlet:1.19.0'
```
<!-- tab:其它 -->
``` xml
implementation 'cn.dev33:sa-token-core:1.17.0'
implementation 'cn.dev33:sa-token-core:1.19.0'
```
<!-- tabs:end -->
@@ -82,21 +84,23 @@ implementation 'cn.dev33:sa-token-core:1.17.0'
``` js
── sa-token
├── sa-token-core // sa-token 核心模块
├── sa-token-servlet // sa-token 整合 Servlet容器实现类包
├── sa-token-spring-boot-starter // sa-token 整合 SpringBoot 快速集成
├── sa-token-reactor-spring-boot-starter // sa-token 整合 Reactor响应式编程 快速集成
├── sa-token-dao-redis // sa-token 整合 Redis (使用jdk默认序列化方式)
├── sa-token-dao-redis-jackson // sa-token 整合 Redis (使用jackson序列化方式)
├── sa-token-spring-aop // sa-token 整合 SpringAOP 注解鉴权
├── sa-token-oauth2 // sa-token 实现 OAuth2.0 模块(内测暂未发布)
├── sa-token-demo-springboot // [示例] sa-token 整合 SpringBoot
├── sa-token-demo-jwt // [示例] sa-token 集成 jwt [示例]
├── sa-token-demo-webflux // [示例] sa-token 整合 WebFlux [示例]
├── sa-token-demo-oauth2 // [示例] sa-token集成OAuth2.0模块 [示例]
├── sa-token-demo-oauth2-client // [示例] OAuth2.0 客户端
├── sa-token-demo-oauth2-server // [示例] OAuth2.0 服务端
├── sa-token-doc // [文档] sa-token开发文档
├── sa-token-core // [核心] sa-token 核心模块
├── sa-token-starter // [整合] sa-token 与其它框架整合
├── sa-token-servlet // [整合] sa-token 整合 Servlet容器实现类包
├── sa-token-spring-boot-starter // [整合] sa-token 整合 SpringBoot 快速集成
├── sa-token-reactor-spring-boot-starter // [整合] sa-token 整合 Reactor响应式编程 快速集成
├── sa-token-plugin // [插件] sa-token 插件合集
├── sa-token-dao-redis // [插件] sa-token 整合 Redis (使用jdk默认序列化方式)
├── sa-token-dao-redis-jackson // [插件] sa-token 整合 Redis (使用jackson序列化方式)
├── sa-token-spring-aop // [插件] sa-token 整合 SpringAOP 注解鉴权
├── sa-token-oauth2 // [插件] sa-token 实现 OAuth2.0 模块(内测暂未发布)
├── sa-token-demo // [示例] sa-token 示例合集
├── sa-token-demo-springboot // [示例] sa-token 整合 SpringBoot
├── sa-token-demo-webflux // [示例] sa-token 整合 WebFlux [示例]
├── sa-token-demo-jwt // [示例] sa-token 集成 jwt [示例]
├── sa-token-demo-oauth2-server // [示例] sa-token 集成 OAuth2.0 (服务端)
├── sa-token-demo-oauth2-client // [示例] sa-token 集成 OAuth2.0 (客户端)
├── sa-token-doc // [文档] sa-token 开发文档
├──pom.xml
```

View File

@@ -1,7 +1,7 @@
# SpringBoot 集成 Sa-Token 示例
本篇将带你从零开始集成sa-token从而让你快速熟悉sa-token的使用姿势 <br>
整合示例在官方仓库的`/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习
整合示例在官方仓库的`/sa-token-demo/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习
---
@@ -17,7 +17,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.17.0</version>
<version>1.19.0</version>
</dependency>
```
@@ -61,7 +61,7 @@ spring:
public class SaTokenDemoApplication {
public static void main(String[] args) throws JsonProcessingException {
SpringApplication.run(SaTokenDemoApplication.class, args);
System.out.println("启动成功sa-token配置如下" + SaTokenManager.getConfig());
System.out.println("启动成功sa-token配置如下" + SaManager.getConfig());
}
}
```

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