mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-02-27 16:50:24 +08:00
Compare commits
99 Commits
v1.14.4-al
...
v1.19.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5fe7897ee | ||
|
|
041294e790 | ||
|
|
0a7a8138b3 | ||
|
|
ca2599c528 | ||
|
|
4398a5808c | ||
|
|
9965821b51 | ||
|
|
5cde169e7f | ||
|
|
479b40b92b | ||
|
|
76dd333c9b | ||
|
|
e6e53d44d5 | ||
|
|
3c429cbee9 | ||
|
|
8b8c01a76d | ||
|
|
9465357d6b | ||
|
|
fb4733792d | ||
|
|
a75d461275 | ||
|
|
9c1ff87023 | ||
|
|
6d164a0726 | ||
|
|
2bb2248522 | ||
|
|
a69e41b04c | ||
|
|
2d4267b1da | ||
|
|
3405188531 | ||
|
|
7a6d027d59 | ||
|
|
eae7f9ffbf | ||
|
|
865a280365 | ||
|
|
b34aed5f97 | ||
|
|
cd99053640 | ||
|
|
c0eeaa6ddd | ||
|
|
72530a223a | ||
|
|
ec42359377 | ||
|
|
d01db3442b | ||
|
|
4ee161031f | ||
|
|
79d7967e0d | ||
|
|
d139bfd858 | ||
|
|
f2454dd244 | ||
|
|
9a2e14d147 | ||
|
|
b7d1ca88af | ||
|
|
36744a64ee | ||
|
|
377801d800 | ||
|
|
6d301a0a69 | ||
|
|
26cde5d244 | ||
|
|
5269e30331 | ||
|
|
e40a39e3ef | ||
|
|
f1104b6a43 | ||
|
|
87b524201a | ||
|
|
34a3f68ad8 | ||
|
|
078119e12c | ||
|
|
5e97c5d7fa | ||
|
|
b7859b67d3 | ||
|
|
2fcf71af41 | ||
|
|
c8f9aafe37 | ||
|
|
7d985602c5 | ||
|
|
dca7830f1b | ||
|
|
a4ae818376 | ||
|
|
740ad2e132 | ||
|
|
78b3ba8bfb | ||
|
|
40fc0810dd | ||
|
|
be2258ee1d | ||
|
|
b1413a3436 | ||
|
|
9c467793f0 | ||
|
|
985eaac79a | ||
|
|
98f94c8b97 | ||
|
|
b66919276d | ||
|
|
38bfb45b26 | ||
|
|
094f8eb3ae | ||
|
|
7de6a1d618 | ||
|
|
59d8b56b18 | ||
|
|
5ba3d07ea7 | ||
|
|
15b0da6351 | ||
|
|
8c6cd9a668 | ||
|
|
f5f8a3edf6 | ||
|
|
860642af57 | ||
|
|
15eefbed33 | ||
|
|
9b44e05c28 | ||
|
|
89b1a2a353 | ||
|
|
bd5907ce52 | ||
|
|
2e79d26817 | ||
|
|
37f1642f7e | ||
|
|
884f3a57da | ||
|
|
f4cf338d12 | ||
|
|
cbd1df6895 | ||
|
|
c48ed3e468 | ||
|
|
70d920b43e | ||
|
|
9fa5f750f9 | ||
|
|
14bdde6735 | ||
|
|
f857c8f246 | ||
|
|
e09c019545 | ||
|
|
7f556c2110 | ||
|
|
9f68a2d4bd | ||
|
|
c441f4246d | ||
|
|
70ef691291 | ||
|
|
3bdc65839e | ||
|
|
1d4639ec0b | ||
|
|
64c06a3daf | ||
|
|
a6cf265e4d | ||
|
|
921e693e7e | ||
|
|
a8117a8021 | ||
|
|
c574e7f8d7 | ||
|
|
36afaf74d3 | ||
|
|
55b9c87d6a |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,4 +11,4 @@ unpackage/
|
||||
.factorypath
|
||||
/.factorypath
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
108
README.md
108
README.md
@@ -1,16 +1,16 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/sz6/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
|
||||
<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.14.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的Java权限认证框架!</h4>
|
||||
<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/sz6/sa-token/stargazers"><img src="https://gitee.com/sz6/sa-token/badge/star.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.14.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token/stargazers"><img src="https://img.shields.io/github/stars/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/watchers"><img src="https://img.shields.io/github/watchers/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/network/members"><img src="https://img.shields.io/github/forks/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/issues"><img src="https://img.shields.io/github/issues/click33/sa-token.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token/blob/master/LICENSE"><img src="https://img.shields.io/github/license/click33/sa-token.svg"></a>
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
|
||||
<a href="https://gitee.com/dromara/sa-token/members"><img src="https://gitee.com/dromara/sa-token/badge/fork.svg"></a>
|
||||
<a href="https://github.com/dromara/sa-token/stargazers"><img src="https://img.shields.io/github/stars/dromara/sa-token?style=flat-square&logo=GitHub"></a>
|
||||
<a href="https://github.com/dromara/sa-token/network/members"><img src="https://img.shields.io/github/forks/dromara/sa-token?style=flat-square&logo=GitHub"></a>
|
||||
<a href="https://github.com/dromara/sa-token/watchers"><img src="https://img.shields.io/github/watchers/dromara/sa-token?style=flat-square&logo=GitHub"></a>
|
||||
<a href="https://github.com/dromara/sa-token/issues"><img src="https://img.shields.io/github/issues/dromara/sa-token.svg?style=flat-square&logo=GitHub"></a>
|
||||
<a href="https://github.com/dromara/sa-token/blob/master/LICENSE"><img src="https://img.shields.io/github/license/dromara/sa-token.svg?style=flat-square"></a>
|
||||
</h4>
|
||||
|
||||
---
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
- [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
|
||||
- [开源不易,求鼓励,点个star吧](###)
|
||||
- [开源不易,求鼓励,点个star吧 !](###)
|
||||
|
||||
|
||||
## Sa-Token是什么?
|
||||
sa-token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题
|
||||
Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题
|
||||
|
||||
框架针对踢人下线、自动续签、前后台分离、分布式会话……等常见业务进行N多适配,通过sa-token,你可以以一种极简的方式实现系统的权限认证部分
|
||||
|
||||
@@ -41,12 +41,17 @@ sa-token是一个轻量级Java权限认证框架,主要解决:登录认证
|
||||
有了sa-token,你所有的权限认证问题,都不再是问题!
|
||||
|
||||
## Sa-Token 能做什么?
|
||||
|
||||

|
||||
|
||||
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- **权限验证** —— 适配RBAC权限模型,不同角色不同授权
|
||||
- **Session会话** —— 专业的数据缓存中心
|
||||
- **踢人下线** —— 将违规用户立刻清退下线
|
||||
- **账号封禁** —— 封禁指定账号,使其无法登陆,还可指定解封时间
|
||||
- **持久层扩展** —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
|
||||
- **分布式会话** —— 提供jwt集成和共享数据中心两种分布式会话方案
|
||||
- **微服务网关鉴权** —— 适配Gateway、Soul、Zuul等常见网关组件的请求拦截认证
|
||||
- **单点登录** —— 一处登录,处处通行
|
||||
- **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- **临时身份切换** —— 将会话身份临时切换为其它账号
|
||||
@@ -60,7 +65,8 @@ sa-token是一个轻量级Java权限认证框架,主要解决:登录认证
|
||||
- **会话治理** —— 提供方便灵活的会话查询接口
|
||||
- **记住我模式** —— 适配[记住我]模式,重启浏览器免验证
|
||||
- **密码加密** —— 提供密码加密模块,可快速MD5、SHA1、SHA256、AES、RSA加密
|
||||
- **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- **全局侦听器** —— 在用户登陆、注销、被踢下线等关键性操作时进行一些AOP操作
|
||||
- **开箱即用** —— 提供SpringMVC、WebFlux等常见web框架starter集成包,真正的开箱即用
|
||||
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
|
||||
|
||||
@@ -116,83 +122,49 @@ StpUtil.setLoginId(10001, "PC"); // 指定设备标识登录
|
||||
StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
|
||||
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号
|
||||
```
|
||||
sa-token的API众多,请恕此处无法为您逐一展示,更多示例请戳官方在线文档
|
||||
sa-token API 众多,请恕此处无法为您逐一展示,更多示例请戳官方在线文档
|
||||
|
||||
|
||||
## 迭代模式
|
||||
sa-token的功能提案主要来源于社区,这意味着人人都可以参与到sa-token的功能定制,决定框架的未来走向,
|
||||
如果你有好的想法,可以在issues提出或者加入群一起交流,对于社区的提出的功能要求,主要分为以下几类:
|
||||
- 对框架新增特性功能且比较简单,会在第一时间进行开发
|
||||
- 对框架新增特性功能但比较复杂,会延后几个版本制定相应的计划后进行开发
|
||||
- 与框架设计理念不太相符,或超出权限认证范畴,将会视需求人数决定是否开发
|
||||
## Star 趋势
|
||||
[](https://giteye.net/chart/77YQZ6UK)
|
||||
|
||||
[](https://starchart.cc/dromara/sa-token)
|
||||
|
||||
|
||||
## 参与贡献
|
||||
众人拾柴火焰高,万丈高楼众人起!
|
||||
sa-token秉承着开放的思想,欢迎大家贡献代码,为框架添砖加瓦,对框架有卓越贡献者将会出现在贡献者名单里
|
||||
sa-token秉承着开放的思想,欢迎大家为框架添砖加瓦:
|
||||
|
||||
1. 在gitee或者github上fork一份代码到自己的仓库
|
||||
2. clone自己的仓库到本地电脑
|
||||
3. 在本地电脑修改、commit、push
|
||||
4. 提交pr(点击:New Pull Request)
|
||||
5. 等待合并
|
||||
1. 核心代码:该部分需要开发者了解整个框架的架构,遵循已有代码规范进行bug修复或提交新功能
|
||||
2. 文档部分:需要以清晰明了的语句书写文档,力求简单易读,授人以鱼同时更授人以渔
|
||||
3. 社区建设:如果框架帮助到了您,希望您可以加入qq群参与交流,对不熟悉框架的新人进行排难解惑
|
||||
4. 框架推广:一个优秀的开源项目不能仅靠闭门造车,它还需要一定的推广方案让更多的人一起参与到项目中
|
||||
5. 其它部分:您可以参考项目issues与需求墙进行贡献
|
||||
|
||||
作者寄语:参与贡献不光只有提交代码一个选择,点一个star、提一个issues都是对开源项目的促进,
|
||||
如果框架帮助到了你,欢迎你把框架推荐给你的朋友、同事使用,为sa-token的推广做一份贡献
|
||||
|
||||
|
||||
## 建议贡献的地方
|
||||
目前框架的主要有以下部分需要大家一起参与贡献:
|
||||
- 核心代码:该部分需要开发者了解整个框架的架构,遵循已有代码规范进行bug修复或提交新功能
|
||||
- 文档部分:需要以清晰明了的语句书写文档,力求简单易读,授人以鱼同时更授人以渔
|
||||
- 社区建设:如果框架帮助到了您,希望您可以加入qq群参与交流,对不熟悉框架的新人进行排难解惑
|
||||
- 框架推广:一个优秀的开源项目不能仅靠闭门造车,它还需要一定的推广方案让更多的人一起参与到项目中
|
||||
- 其它部分:您可以参考项目issues与需求墙进行贡献
|
||||
|
||||
|
||||
## 贡献者名单
|
||||
[省长](https://gitee.com/sz6)、
|
||||
[RockMan](https://gitee.com/njx33)、
|
||||
[click33](https://github.com/click33)、
|
||||
[AppleOfGray](https://gitee.com/appleOfGray)、
|
||||
[Auster](https://github.com/auster9021)、
|
||||
[ZhuBJ0510](https://gitee.com/zhubj0510)、
|
||||
[legg](https://gitee.com/legg321)、
|
||||
[xiaoshitou](https://gitee.com/smallstoneZ)、
|
||||
[zhangjiaxiaozhuo](https://gitee.com/zhangjiaxiaozhuo)、
|
||||
[离你多远](https://gitee.com/liniduoyuan)
|
||||
|
||||
|
||||
## 知乎专栏
|
||||
- [初识sa-token,一行代码搞定登录授权!](https://zhuanlan.zhihu.com/p/344106099)
|
||||
- [一个登录功能也能玩出这么多花样?sa-token带你轻松搞定多地登录、单地登录、同端互斥登录](https://zhuanlan.zhihu.com/p/344511415)
|
||||
- [浅谈踢人下线的设计思路!(附代码实现方案)](https://zhuanlan.zhihu.com/p/345844002)
|
||||
- 文章已在 [csdn](https://blog.csdn.net/shengzhang_/article/details/112593247)、
|
||||
[掘金](https://juejin.cn/post/6917250126650015751)、
|
||||
[开源中国](https://my.oschina.net/u/3503445/blog/4897816)、
|
||||
[博客园](https://www.cnblogs.com/shengzhang/p/14275558.html)、
|
||||
[知乎](https://zhuanlan.zhihu.com/p/344106099)
|
||||
等平台连载中...欢迎投稿
|
||||
作者寄语:参与贡献不光只有提交代码,点一个star、提一个issues都是对开源项目的促进,
|
||||
如果sa-token帮助到了你,欢迎你把框架推荐给朋友、同事使用,为sa-token的推广做一份贡献
|
||||
|
||||
|
||||
## 使用sa-token的开源项目
|
||||
[**[ sa-plus]** 一个基于springboot架构的快速开发框架,内置代码生成器](https://gitee.com/sz6/sa-plus)
|
||||
[**[ sa-plus]** 一个基于springboot架构的快速开发框架,内置代码生成器](https://gitee.com/click33/sa-plus)
|
||||
|
||||
[**[ 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
|
||||
|
||||
|
||||
## 友情链接
|
||||
[**[ OkHttps ]** 一个轻量级http通信框架,API设计无比优雅,支持 WebSocket 以及 Stomp 协议](https://gitee.com/ejlchina-zhxu/okhttps)
|
||||
[**[ okhttps ]** 一个轻量级http通信框架,API设计无比优雅,支持 WebSocket 以及 Stomp 协议](https://gitee.com/ejlchina-zhxu/okhttps)
|
||||
|
||||
[**[ 小诺快速开发平台 ]** 基于SpringBoot2 + AntDesignVue全新快速开发平台,同时拥有三个版本](https://xiaonuo.vip/index#pricing)
|
||||
|
||||
|
||||
## 交流群
|
||||
QQ交流群:[1002350610 点击加入](https://jq.qq.com/?_wv=1027&k=45H977HM)
|
||||
QQ交流群:1002350610 [点击加入](https://jq.qq.com/?_wv=1027&k=45H977HM)
|
||||
|
||||

|
||||
|
||||
**微信群**
|
||||
微信交流群:
|
||||
|
||||

|
||||
|
||||
|
||||
39
mvn clean.bat
Normal file
39
mvn clean.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
:: 整体clean
|
||||
call mvn clean
|
||||
|
||||
:: demo模块clean
|
||||
cd sa-token-demo
|
||||
|
||||
cd sa-token-demo-jwt
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-springboot
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-webflux
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-oauth2-client
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-oauth2-server
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-quick-login
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd ..
|
||||
|
||||
:: 最后打印
|
||||
echo;
|
||||
echo;
|
||||
echo ----------- clean end -----------
|
||||
echo;
|
||||
pause
|
||||
20
pom.xml
20
pom.xml
@@ -8,22 +8,20 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.14.0</version>
|
||||
<version>1.19.0</version>
|
||||
|
||||
<!-- 项目介绍 -->
|
||||
<name>sa-token</name>
|
||||
<description>A Java Web lightweight authority authentication framework, comprehensive function, easy to use</description>
|
||||
<url>https://github.com/click33/sa-token</url>
|
||||
<url>https://github.com/dromara/sa-token</url>
|
||||
|
||||
|
||||
<!-- 所有模块 -->
|
||||
<modules>
|
||||
<module>sa-token-core</module>
|
||||
<module>sa-token-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 -->
|
||||
@@ -38,7 +36,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.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>
|
||||
@@ -47,9 +45,9 @@
|
||||
<!-- 仓库信息 -->
|
||||
<scm>
|
||||
<tag>master</tag>
|
||||
<url>https://github.com/click33/sa-token.git</url>
|
||||
<connection>scm:git:https://github.com/click33/sa-token.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/click33/sa-token.git</developerConnection>
|
||||
<url>https://github.com/dromara/sa-token.git</url>
|
||||
<connection>scm:git:https://github.com/dromara/sa-token.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/dromara/sa-token.git</developerConnection>
|
||||
</scm>
|
||||
|
||||
<!-- 作者信息 -->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.19.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -16,11 +16,7 @@
|
||||
<description>A Java Web lightweight authority authentication framework, comprehensive function, easy to use</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<!-- Zero dependence! -->
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
188
sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
Normal file
188
sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
Normal file
@@ -0,0 +1,188 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.action.SaTokenAction;
|
||||
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.config.SaTokenConfigFactory;
|
||||
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.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaManager {
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
private static SaTokenConfig config;
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaFoxUtil.printSaToken();
|
||||
}
|
||||
// 调用一次StpUtil中的方法,保证其可以尽早的初始化 StpLogic
|
||||
StpUtil.getLoginKey();
|
||||
}
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 持久化 Bean
|
||||
*/
|
||||
private static SaTokenDao saTokenDao;
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaManager.saTokenDao != null && (SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
|
||||
}
|
||||
SaManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限认证 Bean
|
||||
*/
|
||||
private static StpInterface stpInterface;
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaManager.stpInterface = stpInterface;
|
||||
}
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return stpInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* 框架行为 Bean
|
||||
*/
|
||||
private static SaTokenAction saTokenAction;
|
||||
public static void setSaTokenAction(SaTokenAction saTokenAction) {
|
||||
SaManager.saTokenAction = saTokenAction;
|
||||
}
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 容器操作 Bean
|
||||
*/
|
||||
private static SaTokenContext saTokenContext;
|
||||
public static void setSaTokenContext(SaTokenContext saTokenContext) {
|
||||
SaManager.saTokenContext = saTokenContext;
|
||||
}
|
||||
public static SaTokenContext getSaTokenContext() {
|
||||
if (saTokenContext == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenContext == null) {
|
||||
setSaTokenContext(new SaTokenContextDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 侦听器 Bean
|
||||
*/
|
||||
private static SaTokenListener saTokenListener;
|
||||
public static void setSaTokenListener(SaTokenListener saTokenListener) {
|
||||
SaManager.saTokenListener = saTokenListener;
|
||||
}
|
||||
public static SaTokenListener getSaTokenListener() {
|
||||
if (saTokenListener == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenListener == null) {
|
||||
setSaTokenListener(new SaTokenListenerDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic集合, 记录框架所有成功初始化的StpLogic
|
||||
*/
|
||||
public static Map<String, StpLogic> stpLogicMap = new HashMap<String, StpLogic>();
|
||||
|
||||
/**
|
||||
* 向集合中 put 一个 StpLogic
|
||||
* @param stpLogic StpLogic
|
||||
*/
|
||||
public static void putStpLogic(StpLogic stpLogic) {
|
||||
stpLogicMap.put(stpLogic.getLoginKey(), stpLogic);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 LoginKey 获取对应的StpLogic,如果不存在则抛出异常
|
||||
* @param loginKey 对应的LoginKey
|
||||
* @return 对应的StpLogic
|
||||
*/
|
||||
public static StpLogic getStpLogic(String 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("未能获取对应StpLogic,key="+ loginKey);
|
||||
}
|
||||
|
||||
// 返回
|
||||
return stpLogic;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.action.SaTokenAction;
|
||||
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.config.SaTokenConfigFactory;
|
||||
import cn.dev33.satoken.cookie.SaTokenCookie;
|
||||
import cn.dev33.satoken.cookie.SaTokenCookieDefaultImpl;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
|
||||
import cn.dev33.satoken.servlet.SaTokenServlet;
|
||||
import cn.dev33.satoken.servlet.SaTokenServletDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenManager {
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
private static SaTokenConfig config;
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaTokenManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaTokenInsideUtil.printSaToken();
|
||||
}
|
||||
}
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 持久化 Bean
|
||||
*/
|
||||
private static SaTokenDao saTokenDao;
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshTimer();
|
||||
}
|
||||
SaTokenManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限认证 Bean
|
||||
*/
|
||||
private static StpInterface stpInterface;
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaTokenManager.stpInterface = stpInterface;
|
||||
}
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return stpInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* 框架行为 Bean
|
||||
*/
|
||||
private static SaTokenAction saTokenAction;
|
||||
public static void setSaTokenAction(SaTokenAction saTokenAction) {
|
||||
SaTokenManager.saTokenAction = saTokenAction;
|
||||
}
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie操作 Bean
|
||||
*/
|
||||
private static SaTokenCookie saTokenCookie;
|
||||
public static void setSaTokenCookie(SaTokenCookie saTokenCookie) {
|
||||
SaTokenManager.saTokenCookie = saTokenCookie;
|
||||
}
|
||||
public static SaTokenCookie getSaTokenCookie() {
|
||||
if (saTokenCookie == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenCookie == null) {
|
||||
setSaTokenCookie(new SaTokenCookieDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet操作 Bean
|
||||
*/
|
||||
private static SaTokenServlet saTokenServlet;
|
||||
public static void setSaTokenServlet(SaTokenServlet saTokenServlet) {
|
||||
SaTokenManager.saTokenServlet = saTokenServlet;
|
||||
}
|
||||
public static SaTokenServlet getSaTokenServlet() {
|
||||
if (saTokenServlet == null) {
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
if (saTokenServlet == null) {
|
||||
setSaTokenServlet(new SaTokenServletDefaultImpl());
|
||||
}
|
||||
}
|
||||
return saTokenServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic集合, 记录框架所有成功初始化的StpLogic
|
||||
*/
|
||||
public static Map<String, StpLogic> stpLogicMap = new HashMap<String, StpLogic>();
|
||||
/**
|
||||
* 向集合中 put 一个 StpLogic
|
||||
* @param stpLogic
|
||||
*/
|
||||
public static void putStpLogic(StpLogic stpLogic) {
|
||||
stpLogicMap.put(stpLogic.getLoginKey(), stpLogic);
|
||||
}
|
||||
/**
|
||||
* 根据 LoginKey 获取对应的StpLogic,如果不存在则返回null
|
||||
* @param loginKey 对应的LoginKey
|
||||
* @return 对应的StpLogic
|
||||
*/
|
||||
public static StpLogic getStpLogic(String loginKey) {
|
||||
for (String key : stpLogicMap.keySet()) {
|
||||
if(key.equals(loginKey)) {
|
||||
return stpLogicMap.get(key);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
@@ -24,5 +27,19 @@ public interface SaTokenAction {
|
||||
* @return 创建后的Session
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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_RANDOM_TIK.equals(tokenStyle)) {
|
||||
return SaTokenInsideUtil.getRandomString(2) + "_" + SaTokenInsideUtil.getRandomString(14) + "_" + SaTokenInsideUtil.getRandomString(16) + "__";
|
||||
if(SaTokenConsts.TOKEN_STYLE_TIK.equals(tokenStyle)) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,4 +15,10 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaCheckLogin {
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -26,5 +26,11 @@ public @interface SaCheckPermission {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -26,5 +26,11 @@ public @interface SaCheckRole {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@ public class SaTokenConfig {
|
||||
/** 是否在初始化配置时打印版本字符画 */
|
||||
private Boolean isV = true;
|
||||
|
||||
|
||||
/** 是否打印操作日志 */
|
||||
private Boolean isLog = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return token名称 (同时也是cookie名称)
|
||||
@@ -304,10 +306,23 @@ public class SaTokenConfig {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 是否打印操作日志
|
||||
*/
|
||||
public Boolean getIsLog() {
|
||||
return isLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString
|
||||
* @param isLog 是否打印操作日志
|
||||
*/
|
||||
public SaTokenConfig setIsLog(Boolean isLog) {
|
||||
this.isLog = isLog;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -316,7 +331,7 @@ public class SaTokenConfig {
|
||||
+ isReadBody + ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle="
|
||||
+ tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin="
|
||||
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain
|
||||
+ ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + "]";
|
||||
+ ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + ", isLog=" + isLog + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTokenContext {
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Request] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public SaRequest getRequest();
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Response] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public SaResponse getResponse();
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [存储器] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public SaStorage getStorage();
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
*
|
||||
* @param pattern 路由匹配符
|
||||
* @param path 需要匹配的路径
|
||||
* @return see note
|
||||
*/
|
||||
public boolean matchPath(String pattern, String path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [默认实现类]
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextDefaultImpl implements SaTokenContext {
|
||||
|
||||
/**
|
||||
* 默认的错误提示语
|
||||
*/
|
||||
public static final String ERROR_MESSAGE = "未初始化任何有效上下文处理器";
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Request] 对象
|
||||
*/
|
||||
@Override
|
||||
public SaRequest getRequest() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Response] 对象
|
||||
*/
|
||||
@Override
|
||||
public SaResponse getResponse() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [存储器] 对象
|
||||
*/
|
||||
@Override
|
||||
public SaStorage getStorage() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
|
||||
/**
|
||||
* 上下文环境 [ThreadLocal版本]
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextForThreadLocal implements SaTokenContext {
|
||||
|
||||
@Override
|
||||
public SaRequest getRequest() {
|
||||
return SaTokenContextForThreadLocalStorage.getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaResponse getResponse() {
|
||||
return SaTokenContextForThreadLocalStorage.getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaStorage getStorage() {
|
||||
return SaTokenContextForThreadLocalStorage.getStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* 基于ThreadLocal的上下文对象存储器
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextForThreadLocalStorage {
|
||||
|
||||
/**
|
||||
* 基于 ThreadLocal 的上下文
|
||||
*/
|
||||
static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<Box>();
|
||||
|
||||
/**
|
||||
* 初始化 [容器]
|
||||
* @param request {@link SaRequest}
|
||||
* @param response {@link SaResponse}
|
||||
* @param storage {@link SaStorage}
|
||||
*/
|
||||
public static void setBox(SaRequest request, SaResponse response, SaStorage storage) {
|
||||
Box bok = new Box(request, response, storage);
|
||||
boxThreadLocal.set(bok);
|
||||
};
|
||||
|
||||
/**
|
||||
* 清除 [容器]
|
||||
*/
|
||||
public static void clearBox() {
|
||||
boxThreadLocal.remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 [容器]
|
||||
* @return see note
|
||||
*/
|
||||
public static Box getBox() {
|
||||
return boxThreadLocal.get();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 [容器], 如果为空则抛出异常
|
||||
* @return see note
|
||||
*/
|
||||
public static Box getBoxNotNull() {
|
||||
Box box = boxThreadLocal.get();
|
||||
if(box == null) {
|
||||
throw new SaTokenException("未成功初始化上下文");
|
||||
}
|
||||
return box;
|
||||
};
|
||||
|
||||
/**
|
||||
* 在 [上下文容器] 获取 [Request] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaRequest getRequest() {
|
||||
return getBoxNotNull().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 [上下文容器] 获取 [Response] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaResponse getResponse() {
|
||||
return getBoxNotNull().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 [上下文容器] 获取 [存储器] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaStorage getStorage() {
|
||||
return getBoxNotNull().getStorage();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 临时内部类,存储三个对象
|
||||
* @author kong
|
||||
*/
|
||||
/**
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public static class Box {
|
||||
|
||||
public SaRequest request;
|
||||
|
||||
public SaResponse response;
|
||||
|
||||
public SaStorage storage;
|
||||
|
||||
public Box(SaRequest request, SaResponse response, SaStorage storage){
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
public SaRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setRequest(SaRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public SaResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(SaResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public SaStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public void setStorage(SaStorage storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Box [request=" + request + ", response=" + response + ", storage=" + storage + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package cn.dev33.satoken.context.model;
|
||||
|
||||
/**
|
||||
* Cookie 包装类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaCookie {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.dev33.satoken.context.model;
|
||||
|
||||
/**
|
||||
* Request包装类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaRequest {
|
||||
|
||||
/**
|
||||
* 获取底层源对象
|
||||
* @return see note
|
||||
*/
|
||||
public Object getSource();
|
||||
|
||||
/**
|
||||
* 在 [请求体] 里获取一个值
|
||||
* @param name 键
|
||||
* @return 值
|
||||
*/
|
||||
public String getParameter(String name);
|
||||
|
||||
/**
|
||||
* 在 [请求头] 里获取一个值
|
||||
* @param name 键
|
||||
* @return 值
|
||||
*/
|
||||
public String getHeader(String name);
|
||||
|
||||
/**
|
||||
* 在 [Cookie作用域] 里获取一个值
|
||||
* @param name 键
|
||||
* @return 值
|
||||
*/
|
||||
public String getCookieValue(String name);
|
||||
|
||||
/**
|
||||
* 返回当前请求path (不包括上下文名称)
|
||||
* @return see note
|
||||
*/
|
||||
public String getRequestPath();
|
||||
|
||||
/**
|
||||
* 返回当前请求的类型
|
||||
* @return see note
|
||||
*/
|
||||
public String getMethod();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.dev33.satoken.context.model;
|
||||
|
||||
/**
|
||||
* Response 包装类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaResponse {
|
||||
|
||||
/**
|
||||
* 获取底层源对象
|
||||
* @return see note
|
||||
*/
|
||||
public Object getSource();
|
||||
|
||||
/**
|
||||
* 删除指定Cookie
|
||||
* @param name Cookie名称
|
||||
*/
|
||||
public void deleteCookie(String name);
|
||||
|
||||
/**
|
||||
* 写入指定Cookie
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
* @param path Cookie路径
|
||||
* @param domain Cookie的作用域
|
||||
* @param timeout 过期时间 (秒)
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.dev33.satoken.context.model;
|
||||
|
||||
/**
|
||||
* [存储器] 包装类
|
||||
* <p> 在 Request作用域里: 存值、取值
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaStorage {
|
||||
|
||||
/**
|
||||
* 获取底层源对象
|
||||
* @return see note
|
||||
*/
|
||||
public Object getSource();
|
||||
|
||||
/**
|
||||
* 在 [Request作用域] 里写入一个值
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
public void set(String key, Object value);
|
||||
|
||||
/**
|
||||
* 在 [Request作用域] 里获取一个值
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key);
|
||||
|
||||
/**
|
||||
* 在 [Request作用域] 里删除一个值
|
||||
* @param key 键
|
||||
*/
|
||||
public void delete(String key);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 因为不能确定最终运行的容器属于标准Servlet模型还是非Servlet模型,特封装此包下的包装类进行对接
|
||||
*/
|
||||
package cn.dev33.satoken.context.model;
|
||||
@@ -1,55 +0,0 @@
|
||||
package cn.dev33.satoken.cookie;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* sa-token 对cookie的相关操作 接口类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTokenCookie {
|
||||
|
||||
/**
|
||||
* 在request对象中获取指定Cookie
|
||||
*
|
||||
* @param request request对象
|
||||
* @param cookieName Cookie名称
|
||||
* @return 查找到的Cookie对象
|
||||
*/
|
||||
public Cookie getCookie(HttpServletRequest request, String cookieName);
|
||||
|
||||
/**
|
||||
* 添加Cookie
|
||||
*
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
* @param path Cookie路径
|
||||
* @param domain Cookie的作用域
|
||||
* @param timeout 过期时间 (秒)
|
||||
*/
|
||||
public void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout);
|
||||
|
||||
/**
|
||||
* 删除Cookie
|
||||
*
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
*/
|
||||
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name);
|
||||
|
||||
/**
|
||||
* 修改Cookie的value值
|
||||
*
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
*/
|
||||
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value);
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package cn.dev33.satoken.cookie;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* sa-token 对cookie的相关操作 接口实现类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenCookieDefaultImpl implements SaTokenCookie {
|
||||
|
||||
/**
|
||||
* 获取指定cookie
|
||||
*/
|
||||
@Override
|
||||
public Cookie getCookie(HttpServletRequest request, String cookieName) {
|
||||
return SaTokenCookieUtil.getCookie(request, cookieName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
*/
|
||||
@Override
|
||||
public void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout) {
|
||||
SaTokenCookieUtil.addCookie(response, name, value, path, domain, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除cookie
|
||||
*/
|
||||
@Override
|
||||
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
|
||||
SaTokenCookieUtil.delCookie(request, response, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*/
|
||||
@Override
|
||||
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value) {
|
||||
SaTokenCookieUtil.updateCookie(request, response, name, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package cn.dev33.satoken.cookie;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* Cookie操作工具类
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class SaTokenCookieUtil {
|
||||
|
||||
/**
|
||||
* 在request对象中获取指定Cookie
|
||||
*
|
||||
* @param request request对象
|
||||
* @param cookieName Cookie名称
|
||||
* @return 查找到的Cookie对象
|
||||
*/
|
||||
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie != null && cookieName.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
*
|
||||
* @param response response
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
* @param path Cookie写入路径
|
||||
* @param domain Cookie的作用域
|
||||
* @param timeout Cookie有效期 (秒)
|
||||
*/
|
||||
public static void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout) {
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
if(SaTokenInsideUtil.isEmpty(path) == true) {
|
||||
path = "/";
|
||||
}
|
||||
if(SaTokenInsideUtil.isEmpty(domain) == false) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setPath(path);
|
||||
cookie.setMaxAge(timeout);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Cookie
|
||||
*
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
*/
|
||||
public static void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie != null && (name).equals(cookie.getName())) {
|
||||
addCookie(response, name, null, null, null, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*
|
||||
* @param request request对象
|
||||
* @param response response对象
|
||||
* @param name Cookie名称
|
||||
* @param value Cookie值
|
||||
*/
|
||||
public static void updateCookie(HttpServletRequest request, HttpServletResponse response, String name,
|
||||
String value) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie != null && (name).equals(cookie.getName())) {
|
||||
addCookie(response, name, value, cookie.getPath(), cookie.getDomain(), cookie.getMaxAge());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,10 +11,10 @@ import cn.dev33.satoken.session.SaSession;
|
||||
public interface SaTokenDao {
|
||||
|
||||
/** 常量,表示一个key永不过期 (在一个key被标注为永远不过期时返回此值) */
|
||||
public static final Long NEVER_EXPIRE = -1L;
|
||||
public static final long NEVER_EXPIRE = -1;
|
||||
|
||||
/** 常量,表示系统中不存在这个缓存 (在对不存在的key获取剩余存活时间时返回此值) */
|
||||
public static final Long NOT_VALUE_EXPIRE = -2L;
|
||||
public static final long NOT_VALUE_EXPIRE = -2;
|
||||
|
||||
|
||||
// --------------------- token相关 ---------------------
|
||||
|
||||
@@ -4,13 +4,10 @@ package cn.dev33.satoken.dao;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.util.SaTaskUtil;
|
||||
import cn.dev33.satoken.util.SaTaskUtil.FunctionRunClass;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* sa-token持久层默认的实现类 , 基于内存Map
|
||||
@@ -34,7 +31,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
* 构造函数
|
||||
*/
|
||||
public SaTokenDaoDefaultImpl() {
|
||||
initRefreshTimer();
|
||||
initRefreshThread();
|
||||
}
|
||||
|
||||
|
||||
@@ -166,9 +163,15 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
// --------------------- 定时清理过期数据
|
||||
|
||||
/**
|
||||
* 定时任务对象
|
||||
* 执行数据清理的线程
|
||||
*/
|
||||
public Timer refreshTimer;
|
||||
public Thread refreshThread;
|
||||
|
||||
/**
|
||||
* 是否继续执行数据清理的线程标记
|
||||
*/
|
||||
public boolean refreshFlag;
|
||||
|
||||
|
||||
/**
|
||||
* 清理所有已经过期的key
|
||||
@@ -183,30 +186,46 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
/**
|
||||
* 初始化定时任务
|
||||
*/
|
||||
public void initRefreshTimer() {
|
||||
// 如果已经被初始化过了, 则停止它
|
||||
if(this.refreshTimer != null) {
|
||||
this.endRefreshTimer();
|
||||
}
|
||||
|
||||
// 开始新的定时任务
|
||||
if(SaTokenManager.getConfig().getDataRefreshPeriod() < 0) {
|
||||
public void initRefreshThread() {
|
||||
|
||||
// 如果配置了<=0的值,则不启动定时清理
|
||||
if(SaManager.getConfig().getDataRefreshPeriod() <= 0) {
|
||||
return;
|
||||
}
|
||||
int period = SaTokenManager.getConfig().getDataRefreshPeriod() * 1000;
|
||||
this.refreshTimer = SaTaskUtil.setInterval(new FunctionRunClass() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshDataMap();
|
||||
// 启动定时刷新
|
||||
this.refreshFlag = true;
|
||||
this.refreshThread = new Thread(() -> {
|
||||
for (;;) {
|
||||
try {
|
||||
try {
|
||||
// 如果已经被标记为结束
|
||||
if(refreshFlag == false) {
|
||||
return;
|
||||
}
|
||||
// 执行清理
|
||||
refreshDataMap();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 休眠N秒
|
||||
int dataRefreshPeriod = SaManager.getConfig().getDataRefreshPeriod();
|
||||
if(dataRefreshPeriod <= 0) {
|
||||
dataRefreshPeriod = 1;
|
||||
}
|
||||
Thread.sleep(dataRefreshPeriod * 1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, period, period);
|
||||
});
|
||||
refreshThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束定时任务
|
||||
*/
|
||||
public void endRefreshTimer() {
|
||||
this.refreshTimer.cancel();
|
||||
public void endRefreshThread() {
|
||||
this.refreshFlag = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表账号已被封禁
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class DisableLoginException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130143L;
|
||||
|
||||
/** 异常标记值 */
|
||||
public static final String BE_VALUE = "disable";
|
||||
|
||||
/** 异常提示语 */
|
||||
public static final String BE_MESSAGE = "此账号已被封禁";
|
||||
|
||||
/**
|
||||
* LoginKey
|
||||
*/
|
||||
private String loginKey;
|
||||
|
||||
/**
|
||||
* 被封禁的账号id
|
||||
*/
|
||||
private Object loginId;
|
||||
|
||||
/**
|
||||
* 封禁剩余时间,单位:秒
|
||||
*/
|
||||
private long disableTime;
|
||||
|
||||
/**
|
||||
* 获得LoginKey
|
||||
*
|
||||
* @return See above
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取: 被封禁的账号id
|
||||
*
|
||||
* @return See above
|
||||
*/
|
||||
public Object getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取: 封禁剩余时间,单位:秒
|
||||
* @return See above
|
||||
*/
|
||||
public long getDisableTime() {
|
||||
return disableTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造方法创建一个
|
||||
*
|
||||
* @param loginKey loginKey
|
||||
* @param loginId 被封禁的账号id
|
||||
* @param disableTime 封禁剩余时间,单位:秒
|
||||
*/
|
||||
public DisableLoginException(String loginKey, Object loginId, long disableTime) {
|
||||
super(BE_MESSAGE);
|
||||
this.loginId = loginId;
|
||||
this.loginKey = loginKey;
|
||||
this.disableTime = disableTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class NotPermissionException extends SaTokenException {
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
private static final long serialVersionUID = 6806129545290130141L;
|
||||
|
||||
/** 权限码 */
|
||||
private String code;
|
||||
|
||||
@@ -44,7 +44,6 @@ public class NotRoleException extends SaTokenException {
|
||||
}
|
||||
|
||||
public NotRoleException(String role, String loginKey) {
|
||||
// 这里到底要不要拼接上loginKey呢?纠结
|
||||
super("无此角色:" + role);
|
||||
this.role = role;
|
||||
this.loginKey = loginKey;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.dev33.satoken.filter;
|
||||
|
||||
/**
|
||||
* sa-token全局过滤器-认证策略
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaFilterAuthStrategy {
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
* @param r 无含义参数,留作扩展
|
||||
*/
|
||||
public void run(Object r);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.dev33.satoken.filter;
|
||||
|
||||
/**
|
||||
* sa-token全局过滤器-异常处理策略
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaFilterErrorStrategy {
|
||||
|
||||
/**
|
||||
* 执行方法
|
||||
* @param e 异常对象
|
||||
* @return 输出对象(请提前序列化)
|
||||
*/
|
||||
public Object run(Throwable e);
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package cn.dev33.satoken.fun;
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaFunction {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
|
||||
/**
|
||||
* Sa-Token的侦听器
|
||||
* <p> 你可以通过实现此接口在用户登陆、退出等关键性操作时进行一些AOP操作
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTokenListener {
|
||||
|
||||
/**
|
||||
* 每次登录时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param loginModel 登录参数
|
||||
*/
|
||||
public void doLogin(String loginKey, Object loginId, SaLoginModel loginModel);
|
||||
|
||||
/**
|
||||
* 每次注销时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
*/
|
||||
public void doLogout(String loginKey, Object loginId, String tokenValue);
|
||||
|
||||
/**
|
||||
* 每次被踢下线时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public void doLogoutByLoginId(String loginKey, Object loginId, String tokenValue, String device);
|
||||
|
||||
/**
|
||||
* 每次被顶下线时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public void doReplaced(String loginKey, Object loginId, String tokenValue, String device);
|
||||
|
||||
/**
|
||||
* 每次被封禁时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param disableTime 封禁时长,单位: 秒
|
||||
*/
|
||||
public void doDisable(String loginKey, Object loginId, long disableTime);
|
||||
|
||||
/**
|
||||
* 每次被解封时触发
|
||||
* @param loginKey 账号类别
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void doUntieDisable(String loginKey, Object loginId);
|
||||
|
||||
/**
|
||||
* 每次创建Session时触发
|
||||
* @param id SessionId
|
||||
*/
|
||||
public void doCreateSession(String id);
|
||||
|
||||
/**
|
||||
* 每次注销Session时触发
|
||||
* @param id SessionId
|
||||
*/
|
||||
public void doLogoutSession(String id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token 侦听器的默认实现:log打印
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenListenerDefaultImpl implements SaTokenListener {
|
||||
|
||||
/**
|
||||
* 每次登录时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogin(String loginKey, Object loginId, SaLoginModel loginModel) {
|
||||
println("账号[" + loginId + "]登录成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次注销时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogout(String loginKey, Object loginId, String tokenValue) {
|
||||
println("账号[" + loginId + "]注销成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被踢下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogoutByLoginId(String loginKey, Object loginId, String tokenValue, String device) {
|
||||
println("账号[" + loginId + "]被踢下线 (终端: " + device + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被顶下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doReplaced(String loginKey, Object loginId, String tokenValue, String device) {
|
||||
println("账号[" + loginId + "]被顶下线 (终端: " + device + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被封禁时触发
|
||||
*/
|
||||
@Override
|
||||
public void doDisable(String loginKey, Object loginId, long disableTime) {
|
||||
Date date = new Date(System.currentTimeMillis() + disableTime * 1000);
|
||||
println("账号[" + loginId + "]被封禁 (解封时间: " + SaFoxUtil.formatDate(date) + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被解封时触发
|
||||
*/
|
||||
@Override
|
||||
public void doUntieDisable(String loginKey, Object loginId) {
|
||||
println("账号[" + loginId + "]被解除封禁");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次创建Session时触发
|
||||
*/
|
||||
@Override
|
||||
public void doCreateSession(String id) {
|
||||
println("Session[" + id + "]创建成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次注销Session时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogoutSession(String id) {
|
||||
println("Session[" + id + "]注销成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志输出的前缀
|
||||
*/
|
||||
public static final String LOG_PREFIX = "SaLog -->: ";
|
||||
|
||||
/**
|
||||
* 打印指定字符串
|
||||
* @param str 字符串
|
||||
*/
|
||||
public void println(String str) {
|
||||
if(SaManager.getConfig().getIsLog()) {
|
||||
System.out.println(LOG_PREFIX + str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.dev33.satoken.router;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
|
||||
/**
|
||||
* 执行验证方法的辅助类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaRouteFunction {
|
||||
|
||||
/**
|
||||
* 执行验证的方法
|
||||
*
|
||||
* @param request Request包装对象
|
||||
* @param response Response包装对象
|
||||
* @param handler 处理对象
|
||||
*/
|
||||
public void run(SaRequest request, SaResponse response, Object handler);
|
||||
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
package cn.dev33.satoken.interceptor;
|
||||
package cn.dev33.satoken.router;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.autowired.SaTokenSpringAutowired;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.fun.IsRunFunction;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
|
||||
@@ -18,32 +15,6 @@ import cn.dev33.satoken.fun.SaFunction;
|
||||
*/
|
||||
public class SaRouterUtil {
|
||||
|
||||
/**
|
||||
* 在进行路由匹配时所使用的 PathMatcher 对象
|
||||
*/
|
||||
private static PathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* @return 在进行路由匹配时所使用的的 PathMatcher 对象
|
||||
*/
|
||||
public static PathMatcher getPathMatcher() {
|
||||
if(pathMatcher == null) {
|
||||
pathMatcher = SaTokenSpringAutowired.pathMatcher;
|
||||
if(pathMatcher == null) {
|
||||
pathMatcher = new AntPathMatcher();
|
||||
}
|
||||
}
|
||||
return pathMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathMatcher 写入: 在进行路由匹配时所使用的的 PathMatcher 对象
|
||||
*/
|
||||
public static void setPathMatcher(PathMatcher pathMatcher) {
|
||||
SaRouterUtil.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 路由匹配相关 --------------------
|
||||
|
||||
/**
|
||||
@@ -53,10 +24,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String path) {
|
||||
if(getPathMatcher().match(pattern, path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return SaManager.getSaTokenContext().matchPath(pattern, path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +48,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(String pattern) {
|
||||
return isMatch(pattern, SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
|
||||
return isMatch(pattern, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +57,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(List<String> patterns) {
|
||||
return isMatch(patterns, SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
|
||||
return isMatch(patterns, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +120,7 @@ public class SaRouterUtil {
|
||||
* @return 匹配结果包装对象
|
||||
*/
|
||||
public static IsRunFunction match(String... patterns) {
|
||||
boolean matchResult = isMatch(Arrays.asList(patterns), SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
|
||||
boolean matchResult = isMatch(Arrays.asList(patterns), SaHolder.getRequest().getRequestPath());
|
||||
return new IsRunFunction(matchResult);
|
||||
}
|
||||
|
||||
@@ -439,5 +439,4 @@ public class SaSecureUtil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package cn.dev33.satoken.servlet;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Servlet相关操作接口
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTokenServlet {
|
||||
|
||||
/**
|
||||
* 获取当前请求的 Request 对象
|
||||
*
|
||||
* @return 当前请求的Request对象
|
||||
*/
|
||||
public HttpServletRequest getRequest();
|
||||
|
||||
/**
|
||||
* 获取当前请求的 Response 对象
|
||||
*
|
||||
* @return 当前请求的response对象
|
||||
*/
|
||||
public HttpServletResponse getResponse();
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package cn.dev33.satoken.servlet;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* sa-token 对SaTokenServlet接口默认实现类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenServletDefaultImpl implements SaTokenServlet {
|
||||
|
||||
/**
|
||||
* 获取当前请求的Request对象
|
||||
*/
|
||||
@Override
|
||||
public HttpServletRequest getRequest() {
|
||||
throw new SaTokenException("请实现SaTokenServlet接口后进行Servlet相关操作");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的Response对象
|
||||
*/
|
||||
@Override
|
||||
public HttpServletResponse getResponse() {
|
||||
throw new SaTokenException("请实现SaTokenServlet接口后进行Servlet相关操作");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -9,6 +7,8 @@ import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Session Model
|
||||
*
|
||||
@@ -34,6 +34,7 @@ public class SaSession implements Serializable {
|
||||
* 构建一个Session对象
|
||||
*/
|
||||
public SaSession() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +44,8 @@ public class SaSession implements Serializable {
|
||||
public SaSession(String id) {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doCreateSession(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,15 +243,17 @@ public class SaSession implements Serializable {
|
||||
// ----------------------- 一些操作
|
||||
|
||||
/**
|
||||
* 将这个Session从持久库更新一下
|
||||
* 更新Session(从持久库更新刷新一下)
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getSaTokenDao().updateSession(this);
|
||||
SaManager.getSaTokenDao().updateSession(this);
|
||||
}
|
||||
|
||||
/** 注销会话 (注销后,此session会话将不再存储服务器上) */
|
||||
/** 注销Session (从持久库删除) */
|
||||
public void logout() {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(this.id);
|
||||
SaManager.getSaTokenDao().deleteSession(this.id);
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doLogoutSession(id);
|
||||
}
|
||||
|
||||
/** 当Session上的tokenSign数量为零时,注销会话 */
|
||||
@@ -258,9 +263,195 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此Session的剩余存活时间 (单位: 秒)
|
||||
* @return 此Session的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return SaManager.getSaTokenDao().getSessionTimeout(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的剩余存活时间
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateTimeout(long timeout) {
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的最小剩余存活时间 (只有在Session的过期时间低于指定的minTimeout时才会进行修改)
|
||||
* @param minTimeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateMinTimeout(long minTimeout) {
|
||||
if(getTimeout() < minTimeout) {
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的最大剩余存活时间 (只有在Session的过期时间高于指定的maxTimeout时才会进行修改)
|
||||
* @param maxTimeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateMaxTimeout(long maxTimeout) {
|
||||
if(getTimeout() > maxTimeout) {
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------- 存取值 (类型转换)
|
||||
|
||||
// ---- 取值
|
||||
/**
|
||||
* 取值
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 取值 (指定默认值)
|
||||
* @param <T> 默认值的类型
|
||||
* @param key key
|
||||
* @param defaultValue 取不到值时返回的默认值
|
||||
* @return 值
|
||||
*/
|
||||
public <T> T get(String key, T defaultValue) {
|
||||
return getValueByDefaultValue(get(key), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转String类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = get(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转int类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
return getValueByDefaultValue(get(key), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转long类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
return getValueByDefaultValue(get(key), 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转double类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
return getValueByDefaultValue(get(key), 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转float类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
return getValueByDefaultValue(get(key), 0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (指定转换类型)
|
||||
* @param <T> 泛型
|
||||
* @param key key
|
||||
* @param cs 指定转换类型
|
||||
* @return 值
|
||||
*/
|
||||
public <T> T getModel(String key, Class<T> cs) {
|
||||
return getValueByClass(get(key), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (指定转换类型, 并指定值为Null时返回的默认值)
|
||||
* @param <T> 泛型
|
||||
* @param key key
|
||||
* @param cs 指定转换类型
|
||||
* @param defaultValue 值为Null时返回的默认值
|
||||
* @return 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getModel(String key, Class<T> cs, Object defaultValue) {
|
||||
Object value = get(key);
|
||||
if(valueIsNull(value)) {
|
||||
return (T)defaultValue;
|
||||
}
|
||||
return getValueByClass(value, cs);
|
||||
}
|
||||
|
||||
// ---- 其他
|
||||
/**
|
||||
* 写值
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSession set(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写值(只有在此key原本无值的时候才会写入)
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSession setDefaultValue(String key, Object value) {
|
||||
if(has(key) == false) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有某个key
|
||||
* @param key has
|
||||
* @return 是否含有
|
||||
*/
|
||||
public boolean has(String key) {
|
||||
return !valueIsNull(get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删值
|
||||
* @param key 要删除的key
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSession delete(String key) {
|
||||
dataMap.remove(key);
|
||||
update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// --------- 工具方法
|
||||
|
||||
/**
|
||||
* 判断一个值是否为null
|
||||
* @param value 指定值
|
||||
@@ -271,52 +462,63 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为Object类型
|
||||
* @param key key
|
||||
* @return 值
|
||||
* 将指定值转化为指定类型
|
||||
* @param <T> 泛型
|
||||
* @param obj 值
|
||||
* @param cs 类型
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public Object getObject(String key) {
|
||||
return getAttribute(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getValueByClass(Object obj, Class<T> cs) {
|
||||
// 如果 obj 本来就是 cs 类型
|
||||
if(obj != null && obj.getClass().equals(cs)) {
|
||||
return (T)obj;
|
||||
}
|
||||
// 开始转换
|
||||
String obj2 = String.valueOf(obj);
|
||||
Object obj3 = null;
|
||||
if (cs.equals(String.class)) {
|
||||
obj3 = obj2;
|
||||
} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
|
||||
obj3 = Integer.valueOf(obj2);
|
||||
} else if (cs.equals(long.class) || cs.equals(Long.class)) {
|
||||
obj3 = Long.valueOf(obj2);
|
||||
} else if (cs.equals(short.class) || cs.equals(Short.class)) {
|
||||
obj3 = Short.valueOf(obj2);
|
||||
} else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
|
||||
obj3 = Byte.valueOf(obj2);
|
||||
} else if (cs.equals(float.class) || cs.equals(Float.class)) {
|
||||
obj3 = Float.valueOf(obj2);
|
||||
} else if (cs.equals(double.class) || cs.equals(Double.class)) {
|
||||
obj3 = Double.valueOf(obj2);
|
||||
} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
|
||||
obj3 = Boolean.valueOf(obj2);
|
||||
} else {
|
||||
obj3 = (T)obj;
|
||||
}
|
||||
return (T)obj3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为String类型
|
||||
* @param key key
|
||||
* @return 值
|
||||
* 根据默认值来获取值
|
||||
* @param <T> 泛型
|
||||
* @param value 值
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = getObject(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为int类型,如果value为空,则返回0
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
Object value = getObject(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getValueByDefaultValue(Object value, T defaultValue) {
|
||||
|
||||
// 如果 obj 为 null,则直接返回默认值
|
||||
if(valueIsNull(value)) {
|
||||
return 0;
|
||||
return (T)defaultValue;
|
||||
}
|
||||
return Integer.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为long类型,如果value为空,则返回0
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
Object value = getObject(key);
|
||||
if(valueIsNull(value)) {
|
||||
return 0;
|
||||
}
|
||||
return Long.valueOf(String.valueOf(value));
|
||||
|
||||
// 开始转换
|
||||
Class<T> cs = (Class<T>) defaultValue.getClass();
|
||||
return getValueByClass(value, cs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,8 +31,8 @@ public class SaSessionCustomUtil {
|
||||
* @param sessionId session的id
|
||||
* @return 是否存在
|
||||
*/
|
||||
public boolean isExists(String sessionId) {
|
||||
return SaTokenManager.getSaTokenDao().getSession(splicingSessionKey(sessionId)) != null;
|
||||
public static boolean isExists(String sessionId) {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
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 javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
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;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.DisableLoginException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
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,23 +84,31 @@ public class StpLogic {
|
||||
* @return 生成的tokenValue
|
||||
*/
|
||||
public String createTokenValue(Object loginId) {
|
||||
return SaTokenManager.getSaTokenAction().createToken(loginId, loginKey);
|
||||
return SaManager.getSaTokenAction().createToken(loginId, loginKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话写入当前tokenValue
|
||||
* @param tokenValue token值
|
||||
* @param cookieTimeout Cookie存活时间(秒)
|
||||
*/
|
||||
public void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
// 将token保存到本次request里
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
request.setAttribute(splicingKeyJustCreatedSave(), tokenValue);
|
||||
// 注入Cookie
|
||||
SaTokenConfig config = getConfig();
|
||||
// 将token保存到[存储器]里
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
// 判断是否配置了token前缀
|
||||
String tokenPrefix = config.getTokenPrefix();
|
||||
if(SaFoxUtil.isEmpty(tokenPrefix)) {
|
||||
storage.set(splicingKeyJustCreatedSave(), tokenValue);
|
||||
} else {
|
||||
// 如果配置了token前缀,则拼接上前缀一起写入
|
||||
storage.set(splicingKeyJustCreatedSave(), tokenPrefix + SaTokenConsts.TOKEN_CONNECTOR_CHAT + tokenValue);
|
||||
}
|
||||
|
||||
// 注入Cookie
|
||||
if(config.getIsReadCookie() == true){
|
||||
HttpServletResponse response = SaTokenManager.getSaTokenServlet().getResponse();
|
||||
SaTokenManager.getSaTokenCookie().addCookie(response, getTokenName(), tokenValue,
|
||||
"/", config.getCookieDomain(), cookieTimeout);
|
||||
SaResponse response = SaHolder.getResponse();
|
||||
response.addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), cookieTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,14 +118,15 @@ public class StpLogic {
|
||||
*/
|
||||
public String getTokenValue(){
|
||||
// 0. 获取相应对象
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
SaRequest request = SaHolder.getRequest();
|
||||
SaTokenConfig config = getConfig();
|
||||
String keyTokenName = getTokenName();
|
||||
String tokenValue = null;
|
||||
|
||||
// 1. 尝试从request里读取
|
||||
if(request.getAttribute(splicingKeyJustCreatedSave()) != null) {
|
||||
tokenValue = String.valueOf(request.getAttribute(splicingKeyJustCreatedSave()));
|
||||
// 1. 尝试从Storage里读取
|
||||
if(storage.get(splicingKeyJustCreatedSave()) != null) {
|
||||
tokenValue = String.valueOf(storage.get(splicingKeyJustCreatedSave()));
|
||||
}
|
||||
// 2. 尝试从请求体里面读取
|
||||
if(tokenValue == null && config.getIsReadBody()){
|
||||
@@ -129,18 +138,17 @@ public class StpLogic {
|
||||
}
|
||||
// 4. 尝试从cookie里读取
|
||||
if(tokenValue == null && config.getIsReadCookie()){
|
||||
Cookie cookie = SaTokenManager.getSaTokenCookie().getCookie(request, keyTokenName);
|
||||
if(cookie != null){
|
||||
tokenValue = cookie.getValue();
|
||||
}
|
||||
tokenValue = request.getCookieValue(keyTokenName);
|
||||
}
|
||||
|
||||
// 5. 如果打开了前缀模式
|
||||
String tokenPrefix = getConfig().getTokenPrefix();
|
||||
if(SaTokenInsideUtil.isEmpty(tokenPrefix) == false && SaTokenInsideUtil.isEmpty(tokenValue) == false) {
|
||||
// 如果token以指定的前缀开头, 则裁剪掉它
|
||||
if(tokenValue.startsWith(tokenPrefix + " ")) {
|
||||
tokenValue = tokenValue.substring(tokenPrefix.length() + 1);
|
||||
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());
|
||||
} else {
|
||||
tokenValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +178,8 @@ public class StpLogic {
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
// 登录与注销
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
@@ -203,9 +213,14 @@ public class StpLogic {
|
||||
*/
|
||||
public void setLoginId(Object loginId, SaLoginModel loginModel) {
|
||||
|
||||
// ------ 0、检查此账号是否已被封禁
|
||||
if(isDisable(loginId)) {
|
||||
throw new DisableLoginException(loginKey, loginId, getDisableTime(loginId));
|
||||
}
|
||||
|
||||
// ------ 1、获取相应对象
|
||||
SaTokenConfig config = getConfig();
|
||||
SaTokenDao dao = SaTokenManager.getSaTokenDao();
|
||||
SaTokenDao dao = SaManager.getSaTokenDao();
|
||||
loginModel.build(config);
|
||||
|
||||
// ------ 2、生成一个token
|
||||
@@ -230,6 +245,8 @@ public class StpLogic {
|
||||
clearLastActivity(tokenSign.getValue());
|
||||
// 3. 清理user-session上的token签名记录
|
||||
session.removeTokenSign(tokenSign.getValue());
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doReplaced(loginKey, loginId, tokenSign.getValue(), tokenSign.getDevice());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,21 +261,23 @@ public class StpLogic {
|
||||
if(session == null) {
|
||||
session = getSessionByLoginId(loginId);
|
||||
} else {
|
||||
// 保证此Session的有效期 >= token的有效期
|
||||
if(dao.getSessionTimeout(session.getId()) < loginModel.getTimeout()) {
|
||||
dao.updateSessionTimeout(session.getId(), loginModel.getTimeout());
|
||||
}
|
||||
session.updateMinTimeout(loginModel.getTimeout());
|
||||
}
|
||||
// 在session上记录token签名
|
||||
session.addTokenSign(new TokenSign(tokenValue, loginModel.getDevice()));
|
||||
|
||||
// ------ 4. 持久化其它数据
|
||||
// token -> uid
|
||||
dao.set(splicingKeyTokenValue(tokenValue), String.valueOf(loginId), loginModel.getTimeout());
|
||||
dao.set(splicingKeyTokenValue(tokenValue), String.valueOf(loginId), loginModel.getTimeout());
|
||||
|
||||
// 写入 [最后操作时间]
|
||||
setLastActivityToNow(tokenValue);
|
||||
setLastActivityToNow(tokenValue);
|
||||
|
||||
// 在当前会话写入当前tokenValue
|
||||
setTokenValue(tokenValue, loginModel.getCookieTimeout());
|
||||
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doLogin(loginKey, loginId, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,7 +291,7 @@ public class StpLogic {
|
||||
}
|
||||
// 如果打开了cookie模式,第一步,先把cookie清除掉
|
||||
if(getConfig().getIsReadCookie() == true){
|
||||
SaTokenManager.getSaTokenCookie().delCookie(SaTokenManager.getSaTokenServlet().getRequest(), SaTokenManager.getSaTokenServlet().getResponse(), getTokenName());
|
||||
SaHolder.getResponse().deleteCookie(getTokenName());
|
||||
}
|
||||
logoutByTokenValue(tokenValue);
|
||||
}
|
||||
@@ -284,22 +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));
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -319,8 +344,8 @@ public class StpLogic {
|
||||
* @param device 设备标识 (填null代表所有注销设备)
|
||||
*/
|
||||
public void logoutByLoginId(Object loginId, String device) {
|
||||
// 1. 先获取这个账号的[id-session], 如果为null,则不执行任何操作
|
||||
SaSession session = getSessionByLoginId(loginId);
|
||||
// 1. 先获取这个账号的[user-session], 如果为null,则不执行任何操作
|
||||
SaSession session = getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
@@ -334,15 +359,61 @@ 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);
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doLogoutByLoginId(loginKey, loginId, tokenValue, tokenSign.getDevice());
|
||||
}
|
||||
}
|
||||
// 3. 尝试注销session
|
||||
session.logoutByTokenSignCountToZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 封禁指定账号
|
||||
* <p> 此方法不会直接将此账号id踢下线,而是在对方再次登录时抛出`DisableLoginException`异常
|
||||
* @param loginId 指定账号id
|
||||
* @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁)
|
||||
*/
|
||||
public void disable(Object loginId, long disableTime) {
|
||||
// 标注为已被封禁
|
||||
SaManager.getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime);
|
||||
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doDisable(loginKey, loginId, disableTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
|
||||
* @param loginId 账号id
|
||||
* @return see note
|
||||
*/
|
||||
public boolean isDisable(Object loginId) {
|
||||
return SaManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
|
||||
* @param loginId 账号id
|
||||
* @return see note
|
||||
*/
|
||||
public long getDisableTime(Object loginId) {
|
||||
return SaManager.getSaTokenDao().getTimeout(splicingKeyDisable(loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解封指定账号
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void untieDisable(Object loginId) {
|
||||
SaManager.getSaTokenDao().delete(splicingKeyDisable(loginId));
|
||||
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doUntieDisable(loginKey, loginId);
|
||||
}
|
||||
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
@@ -392,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
|
||||
@@ -496,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));
|
||||
}
|
||||
|
||||
|
||||
@@ -509,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;
|
||||
}
|
||||
@@ -631,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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,9 +716,9 @@ public class StpLogic {
|
||||
return;
|
||||
}
|
||||
// 删除[最后操作时间]
|
||||
SaTokenManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
|
||||
SaManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
|
||||
// 清除标记
|
||||
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY);
|
||||
SaHolder.getStorage().delete((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,8 +731,8 @@ public class StpLogic {
|
||||
return;
|
||||
}
|
||||
// 如果本次请求已经有了[检查标记], 则立即返回
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
if(request.getAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
if(storage.get(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
|
||||
return;
|
||||
}
|
||||
// ------------ 验证是否已经 [临时过期]
|
||||
@@ -677,7 +749,7 @@ public class StpLogic {
|
||||
// --- 至此,验证已通过
|
||||
|
||||
// 打上[检查标记],标记一下当前请求已经通过验证,避免一次请求多次验证,造成不必要的性能消耗
|
||||
request.setAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY, true);
|
||||
storage.set(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -696,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()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -716,7 +788,7 @@ public class StpLogic {
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenTimeout() {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
|
||||
return SaManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -725,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)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -742,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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -759,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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -787,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;
|
||||
@@ -813,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -842,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);
|
||||
}
|
||||
}
|
||||
@@ -856,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;
|
||||
}
|
||||
@@ -878,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -907,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);
|
||||
}
|
||||
}
|
||||
@@ -921,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;
|
||||
}
|
||||
@@ -1032,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1043,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1054,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1119,7 +1193,15 @@ public class StpLogic {
|
||||
public String splicingKeyJustCreatedSave() {
|
||||
return SaTokenConsts.JUST_CREATED_SAVE_KEY + loginKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拼接key: 账号封禁
|
||||
* @param loginId 账号id
|
||||
* @return key
|
||||
*/
|
||||
public String splicingKeyDisable(Object loginId) {
|
||||
return getConfig().getTokenName() + ":" + loginKey + ":disable:" + loginId;
|
||||
}
|
||||
|
||||
// =================== Bean对象代理 ===================
|
||||
|
||||
@@ -1129,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);
|
||||
}
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
}
|
||||
|
||||
|
||||
@@ -1201,14 +1259,14 @@ public class StpLogic {
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public void switchTo(Object loginId) {
|
||||
SaTokenManager.getSaTokenServlet().getRequest().setAttribute(splicingKeySwitch(), loginId);
|
||||
SaHolder.getStorage().set(splicingKeySwitch(), loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束临时切换身份
|
||||
*/
|
||||
public void endSwitch() {
|
||||
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(splicingKeySwitch());
|
||||
SaHolder.getStorage().delete(splicingKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1216,7 +1274,7 @@ public class StpLogic {
|
||||
* @return 是否正处于[身份临时切换]中
|
||||
*/
|
||||
public boolean isSwitch() {
|
||||
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(splicingKeySwitch()) != null;
|
||||
return SaHolder.getStorage().get(splicingKeySwitch()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1224,7 +1282,7 @@ public class StpLogic {
|
||||
* @return 返回[身份临时切换]的loginId
|
||||
*/
|
||||
public Object getSwitchLoginId() {
|
||||
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(splicingKeySwitch());
|
||||
return SaHolder.getStorage().get(splicingKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1244,7 +1302,4 @@ public class StpLogic {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -39,6 +43,7 @@ public class StpUtil {
|
||||
/**
|
||||
* 在当前会话写入当前tokenValue
|
||||
* @param tokenValue token值
|
||||
* @param cookieTimeout Cookie存活时间(秒)
|
||||
*/
|
||||
public static void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
stpLogic.setTokenValue(tokenValue, cookieTimeout);
|
||||
@@ -131,7 +136,42 @@ public class StpUtil {
|
||||
public static void logoutByLoginId(Object loginId, String device) {
|
||||
stpLogic.logoutByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封禁指定账号
|
||||
* <p> 此方法不会直接将此账号id踢下线,而是在对方再次登录时抛出`DisableLoginException`异常
|
||||
* @param loginId 指定账号id
|
||||
* @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁)
|
||||
*/
|
||||
public static void disable(Object loginId, long disableTime) {
|
||||
stpLogic.disable(loginId, disableTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
|
||||
* @param loginId 账号id
|
||||
* @return see note
|
||||
*/
|
||||
public static boolean isDisable(Object loginId) {
|
||||
return stpLogic.isDisable(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
|
||||
* @param loginId 账号id
|
||||
* @return see note
|
||||
*/
|
||||
public static long getDisableTime(Object loginId) {
|
||||
return stpLogic.getDisableTime(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解封指定账号
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void untieDisable(Object loginId) {
|
||||
stpLogic.untieDisable(loginId);
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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 版本字符画
|
||||
*/
|
||||
public static void printSaToken() {
|
||||
String str = "____ ____ ___ ____ _ _ ____ _ _ \r\n" + "[__ |__| __ | | | |_/ |___ |\\ | \r\n"
|
||||
+ "___] | | | |__| | \\_ |___ | \\| \r\n" + "sa-token:" + SaTokenConsts.VERSION_NO
|
||||
+ " \r\n" + "GitHub:" + SaTokenConsts.GITHUB_URL; // + "\r\n";
|
||||
+ "___] | | | |__| | \\_ |___ | \\| "
|
||||
// + "sa-token:"
|
||||
+ "\r\n" + "DevDoc:" + SaTokenConsts.DEV_DOC_URL // + "\r\n";
|
||||
+ " (" + SaTokenConsts.VERSION_NO + ")"
|
||||
+ "\r\n" + "GitHub:" + SaTokenConsts.GITHUB_URL // + "\r\n";
|
||||
;
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
@@ -59,6 +66,15 @@ public class SaTokenInsideUtil {
|
||||
return System.currentTimeMillis() + "" + new Random().nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将日期格式化
|
||||
* @param date 日期
|
||||
* @return 格式化后的时间
|
||||
*/
|
||||
public static String formatDate(Date date){
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
@@ -114,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* 任务调度Util
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTaskUtil {
|
||||
|
||||
/**
|
||||
* 延时指定毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setTimeout(FunctionRunClass fc, int delay) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
timer.cancel();
|
||||
}
|
||||
}, delay);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 延时delay毫秒,每隔period毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @param period 每隔多少毫秒执行一次
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setInterval(FunctionRunClass fc, int delay, int period) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
}
|
||||
}, delay, period);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装一个内部类,便于操作
|
||||
* @author kong
|
||||
*/
|
||||
public static interface FunctionRunClass{
|
||||
/**
|
||||
* 要执行的方法
|
||||
*/
|
||||
public void run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,15 +11,19 @@ public class SaTokenConsts {
|
||||
// =================== sa-token版本信息 ===================
|
||||
|
||||
/**
|
||||
* sa-token 版本号
|
||||
* sa-token 当前版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.14.0";
|
||||
public static final String VERSION_NO = "v1.19.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
*/
|
||||
public static final String GITHUB_URL = "https://github.com/click33/sa-token";
|
||||
public static final String GITHUB_URL = "https://github.com/dromara/sa-token";
|
||||
|
||||
/**
|
||||
* sa-token 开发文档地址
|
||||
*/
|
||||
public static final String DEV_DOC_URL = "http://sa-token.dev33.cn";
|
||||
|
||||
// =================== 常量key标记 ===================
|
||||
|
||||
@@ -42,8 +46,8 @@ public class SaTokenConsts {
|
||||
* 常量key标记: 在进行临时身份切换时使用的key
|
||||
*/
|
||||
public static final String SWITCH_TO_SAVE_KEY = "SWITCH_TO_SAVE_KEY_";
|
||||
|
||||
|
||||
|
||||
|
||||
// =================== token-style 相关 ===================
|
||||
|
||||
/**
|
||||
@@ -74,7 +78,19 @@ public class SaTokenConsts {
|
||||
/**
|
||||
* token风格: tik风格 (2_14_16)
|
||||
*/
|
||||
public static final String TOKEN_STYLE_RANDOM_TIK = "tik";
|
||||
public static final String TOKEN_STYLE_TIK = "tik";
|
||||
|
||||
|
||||
// =================== 其它 ===================
|
||||
|
||||
/**
|
||||
* 连接token前缀和token值的字符
|
||||
*/
|
||||
public static final String TOKEN_CONNECTOR_CHAT = " ";
|
||||
|
||||
/**
|
||||
* 切面、拦截器、过滤器等各种组件的注册优先级顺序
|
||||
*/
|
||||
public static final int ASSEMBLY_ORDER = -100;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +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.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
|
||||
|
||||
/**
|
||||
* sa-token代码方式进行配置
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
|
||||
// 获取配置Bean (以代码的方式配置sa-token, 此配置会覆盖yml中的配置 )
|
||||
// @Primary
|
||||
// @Bean(name="MySaTokenConfig")
|
||||
public SaTokenConfig getSaTokenConfig() {
|
||||
SaTokenConfig config = new SaTokenConfig();
|
||||
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
|
||||
config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天
|
||||
config.setActivityTimeout(-1); // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
config.setAllowConcurrentLogin(true); // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
return config;
|
||||
}
|
||||
|
||||
// 注册sa-token的拦截器,打开注解式鉴权功能
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册注解拦截器
|
||||
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.pj.test;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("user")
|
||||
public class UserController {
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/user/doLogin
|
||||
@RequestMapping("doLogin")
|
||||
public String test(String username, String password) {
|
||||
if("zhang".equals(username) && "123456".equals(password)) {
|
||||
StpUtil.setLoginId(10001);
|
||||
return "登录成功";
|
||||
}
|
||||
return "登录失败";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,16 +2,16 @@ package com.pj.satoken.jwt;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
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;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
@@ -122,15 +122,15 @@ public class SaTokenJwtUtil {
|
||||
|
||||
// 重写 (在当前会话上登录id )
|
||||
@Override
|
||||
public void setLoginId(Object loginId, String device) {
|
||||
public void setLoginId(Object loginId, SaLoginModel loginModel) {
|
||||
// ------ 1、获取相应对象
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
SaStorage storage = SaManager.getSaTokenContext().getStorage();
|
||||
SaTokenConfig config = getConfig();
|
||||
// ------ 2、生成一个token
|
||||
String tokenValue = createTokenValue(loginId);
|
||||
request.setAttribute(splicingKeyJustCreatedSave(), tokenValue); // 将token保存到本次request里
|
||||
storage.set(splicingKeyJustCreatedSave(), tokenValue); // 将token保存到本次request里
|
||||
if(config.getIsReadCookie() == true){ // cookie注入
|
||||
SaTokenManager.getSaTokenCookie().addCookie(SaTokenManager.getSaTokenServlet().getResponse(), 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.getSaTokenCookie().delCookie(SaTokenManager.getSaTokenServlet().getRequest(), SaTokenManager.getSaTokenServlet().getResponse(), getTokenName());
|
||||
SaManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.0.RELEASE</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.0.RELEASE</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -39,7 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.14.0-alpha</version>
|
||||
<version>1.15.0-alpha</version>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token整合redis (使用jackson序列化方式) -->
|
||||
68
sa-token-demo/sa-token-demo-quick-login/pom.xml
Normal file
68
sa-token-demo/sa-token-demo-quick-login/pom.xml
Normal 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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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:}
|
||||
|
||||
12
sa-token-demo/sa-token-demo-springboot/.gitignore
vendored
Normal file
12
sa-token-demo/sa-token-demo-springboot/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.idea/
|
||||
|
||||
.factorypath
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -31,7 +31,7 @@
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
@@ -3,14 +3,19 @@ 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 示例
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SaTokenDemoApplication {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,12 +5,14 @@ import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
import cn.dev33.satoken.exception.DisableLoginException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
@@ -18,7 +20,7 @@ import cn.dev33.satoken.exception.NotRoleException;
|
||||
/**
|
||||
* 全局异常处理
|
||||
*/
|
||||
@RestControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
|
||||
@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
|
||||
public class GlobalException {
|
||||
|
||||
// 在当前类每个方法进入之前触发的操作
|
||||
@@ -28,14 +30,14 @@ public class GlobalException {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 全局异常拦截(拦截项目中的所有异常)
|
||||
@ResponseBody
|
||||
@ExceptionHandler
|
||||
public AjaxJson handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
System.out.println("全局异常---------------");
|
||||
e.printStackTrace();
|
||||
|
||||
// 不同异常返回不同状态码
|
||||
@@ -49,6 +51,9 @@ public class GlobalException {
|
||||
} else if(e instanceof NotPermissionException) { // 如果是权限异常
|
||||
NotPermissionException ee = (NotPermissionException) e;
|
||||
aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
|
||||
} else if(e instanceof DisableLoginException) { // 如果是被封禁异常
|
||||
DisableLoginException ee = (DisableLoginException) e;
|
||||
aj = AjaxJson.getNotJur("账号被封禁:" + ee.getDisableTime() + "秒后解封");
|
||||
} else { // 普通异常, 输出:500 + 异常信息
|
||||
aj = AjaxJson.getError(e.getMessage());
|
||||
}
|
||||
@@ -3,8 +3,6 @@ package com.pj.test;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -241,14 +239,9 @@ public class TestController {
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test(HttpServletResponse response) {
|
||||
public AjaxJson test() {
|
||||
System.out.println("进来了");
|
||||
// StpUtil.setLoginId(10001, new SaLoginModel()
|
||||
// .setDevice("PC") // 此次登录的客户端设备标识, 用于[同端互斥登录]时指定此次登录的设备名称
|
||||
// .setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
// .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
// );
|
||||
StpUtil.getTokenSession();
|
||||
System.out.println(StpUtil.getTokenInfo());
|
||||
return AjaxJson.getSuccess("访问成功");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.pj.test;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* 登录测试
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/user/")
|
||||
public class UserController {
|
||||
|
||||
// 测试登录,浏览器访问: http://localhost:8081/user/doLogin?username=zhang&password=123456
|
||||
@RequestMapping("doLogin")
|
||||
public String doLogin(String username, String password) {
|
||||
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
|
||||
if("zhang".equals(username) && "123456".equals(password)) {
|
||||
StpUtil.setLoginId(10001);
|
||||
return "登录成功";
|
||||
}
|
||||
return "登录失败";
|
||||
}
|
||||
|
||||
// 查询登录状态,浏览器访问: http://localhost:8081/user/isLogin
|
||||
@RequestMapping("isLogin")
|
||||
public String isLogin(String username, String password) {
|
||||
return "当前会话是否登录:" + StpUtil.isLogin();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
allow-concurrent-login: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: false
|
||||
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 0
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 10000ms
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数
|
||||
max-active: 200
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user