Compare commits
199 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9df251aa3 | |||
| 4e166c1be4 | |||
| 7d0037066a | |||
| b836e1f75a | |||
| 40b82ce602 | |||
| 7b69b7915b | |||
| d2e00b341d | |||
| 33318c6835 | |||
| 7c4cb6f4d1 | |||
| c6d5467db7 | |||
| 18757a23d2 | |||
| dd2665ceb1 | |||
| 51e58b74fe | |||
| 6935889d39 | |||
| 6c874e6737 | |||
| 88c9c87de4 | |||
| 1ff29b47af | |||
| 16f67d16f1 | |||
| 7695fbf05e | |||
| 23c00b5d8e | |||
| a73adf6727 | |||
| c6d3cda4a4 | |||
| 1df8465e20 | |||
| 1559406ece | |||
| f6f4d337c9 | |||
| 316bb063d9 | |||
| c8fde60974 | |||
| 736ac66701 | |||
| 9c685ecb83 | |||
| a67e58a2ee | |||
| bb79ca3d16 | |||
| a5b65fb30e | |||
| a514ccf5f3 | |||
| bebee60901 | |||
| 5ea5fbe922 | |||
| 88d7f44401 | |||
| 6eec264e70 | |||
| ac94dbb70c | |||
| 8a0fa6724a | |||
| 8b8977eedf | |||
| bda2601169 | |||
| 4515b06fb6 | |||
| d8081274ab | |||
| c5d726952a | |||
| 3aed3f96ec | |||
| c57a5cfc9d | |||
| 4efb0568e5 | |||
| a761a7b13b | |||
| f4b500ed6f | |||
| 9c6f4cb64a | |||
| bf35d5cd80 | |||
| 9e8ae52032 | |||
| 1bb91d5dbb | |||
| b997a2d870 | |||
| f8f698fc3d | |||
| 705b565e38 | |||
| a2d1121b66 | |||
| d0e59c7a3a | |||
| 0748f7941d | |||
| b3208973bf | |||
| c284863e68 | |||
| e9ab375854 | |||
| a54a8cc455 | |||
| 34a62a2aa0 | |||
| 73bdb6c89a | |||
| ec9f12511c | |||
| afa09ac5e6 | |||
| ce0879c5b5 | |||
| 953ba965aa | |||
| 737aeb5fb0 | |||
| b44ac363d5 | |||
| 6e0242aae5 | |||
| f5bbb0c388 | |||
| 8081869e5e | |||
| f97f9fb06c | |||
| 5fbafc7674 | |||
| b4cec9d854 | |||
| 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 | |||
| 50ffda7bef | |||
| a122a8b083 | |||
| 69ce298a8a | |||
| f92e64b9cf | |||
| d3138cefc8 | |||
| 71f2522f08 | |||
| a5e9bd6714 | |||
| 27bb436a90 | |||
| d75c91f0ab | |||
| 8ee9f215a6 | |||
| 1df216879c | |||
| 91998af186 | |||
| f33df38f64 | |||
| aaf4bb8931 | |||
| 5808710bbf | |||
| 62787c3257 | |||
| 6dd39505f9 | |||
| d86f72b469 | |||
| 7b7920123a | |||
| 8872982455 | |||
| 80f07ae01e | |||
| 540730d9a4 | |||
| 03c8abb269 |
+1
-1
@@ -11,4 +11,4 @@ unpackage/
|
||||
.factorypath
|
||||
/.factorypath
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
@@ -1,86 +1,117 @@
|
||||
<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.21.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的 Java 权限认证框架!</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
|
||||
<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>
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.14.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>
|
||||
</h4>
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 在线资料
|
||||
|
||||
- [官网首页:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
|
||||
- [在线文档:http://sa-token.dev33.cn/doc/index.html](http://sa-token.dev33.cn/doc/index.html)
|
||||
- [在线文档:http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
||||
|
||||
- [需求提交:我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-token)
|
||||
|
||||
- [开源不易,求鼓励,点个star吧](###)
|
||||
- [开源不易,求鼓励,点个star吧 !](###)
|
||||
|
||||
|
||||
## Sa-Token是什么?
|
||||
sa-token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题
|
||||
## Sa-Token 是什么?
|
||||
Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题
|
||||
|
||||
框架针对踢人下线、自动续签、前后台分离、分布式会话……等常见业务进行N多适配,通过sa-token,你可以以一种极简的方式实现系统的权限认证部分
|
||||
|
||||
与其它权限认证框架相比,`sa-token` 具有以下优势:
|
||||
1. **简单** :可零配置启动框架,真正的开箱即用,低成本上手
|
||||
2. **强大** :目前已集成几十项权限相关特性,涵盖了大部分业务场景的解决方案
|
||||
3. **易用** :如丝般顺滑的API调用,大量高级特性统统只需一行代码即可实现
|
||||
4. **高扩展** :几乎所有组件都提供了扩展接口,90%以上的逻辑都可以按需重写
|
||||
|
||||
有了sa-token,你所有的权限认证问题,都不再是问题!
|
||||
框架集成简单、开箱即用、API设计清爽,通过Sa-Token,你将以一种极其简单的方式实现系统的权限认证部分
|
||||
|
||||
## Sa-Token 能做什么?
|
||||
- **登录验证** —— 轻松登录鉴权,并提供五种细分场景值
|
||||
- **权限验证** —— 适配RBAC权限模型,不同角色不同授权
|
||||
- **Session会话** —— 专业的数据缓存中心
|
||||
- **踢人下线** —— 将违规用户立刻清退下线
|
||||
|
||||
- **登录验证** —— 单端登录、多端登录、同端互斥登录、七天内免登录
|
||||
- **权限验证** —— 权限认证、角色认证、会话二级认证
|
||||
- **Session会话** —— 全端共享Session、单端独享Session、自定义Session
|
||||
- **踢人下线** —— 根据账号id踢人下线、根据Token值踢人下线
|
||||
- **账号封禁** —— 指定天数封禁、永久封禁、设定解封时间
|
||||
- **持久层扩展** —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
|
||||
- **分布式会话** —— 提供jwt集成和共享数据中心两种分布式会话方案
|
||||
- **单点登录** —— 一处登录,处处通行
|
||||
- **分布式会话** —— 提供jwt集成、共享数据中心两种分布式会话方案
|
||||
- **微服务网关鉴权** —— 适配Gateway、Soul、Zuul等常见网关的路由拦截认证
|
||||
- **单点登录** —— 内置三种单点登录模式:无论是否跨域、是否共享Redis,都可以搞定
|
||||
- **二级认证** —— 在已登录的基础上再次认证,保证安全性
|
||||
- **独立Redis** —— 将权限缓存与业务缓存分离
|
||||
- **临时Token验证** —— 解决短时间的Token授权问题
|
||||
- **模拟他人账号** —— 实时操作任意用户状态数据
|
||||
- **临时身份切换** —— 将会话身份临时切换为其它账号
|
||||
- **无Cookie模式** —— APP、小程序等前后台分离场景
|
||||
- **前后台分离** —— APP、小程序等不支持Cookie的终端
|
||||
- **同端互斥登录** —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录
|
||||
- **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权
|
||||
- **花式token生成** —— 内置六种token风格,还可自定义token生成策略
|
||||
- **花式token生成** —— 内置六种Token风格,还可:自定义Token生成策略、自定义Token前缀
|
||||
- **注解式鉴权** —— 优雅的将鉴权与业务代码分离
|
||||
- **路由拦截式鉴权** —— 根据路由拦截鉴权,可适配restful模式
|
||||
- **自动续签** —— 提供两种token过期策略,灵活搭配使用,还可自动续签
|
||||
- **自动续签** —— 提供两种Token过期策略,灵活搭配使用,还可自动续签
|
||||
- **会话治理** —— 提供方便灵活的会话查询接口
|
||||
- **组件自动注入** —— 零配置与Spring等框架集成
|
||||
- **记住我模式** —— 适配[记住我]模式,重启浏览器免验证
|
||||
- **密码加密** —— 提供密码加密模块,可快速MD5、SHA1、SHA256、AES、RSA加密
|
||||
- **全局侦听器** —— 在用户登陆、注销、被踢下线等关键性操作时进行一些AOP操作
|
||||
- **开箱即用** —— 提供SpringMVC、WebFlux等常见web框架starter集成包,真正的开箱即用
|
||||
- **更多功能正在集成中...** —— 如有您有好想法或者建议,欢迎加群交流
|
||||
|
||||
##### Sa-Token 功能结构图
|
||||

|
||||
|
||||
##### Sa-Token 认证流程图
|
||||

|
||||
|
||||
|
||||
## Sa-Token-SSO 单点登录
|
||||
对于单点登录,网上教程大多以CAS模式为主,其实对于不同的系统架构,实现单点登录的步骤也大为不同,Sa-Token由简入难将其划分为三种模式:
|
||||
|
||||
| 系统架构 | 采用模式 | 简介 | 文档链接 |
|
||||
| :-------- | :-------- | :-------- | :-------- |
|
||||
| 前端同域 + 后端同 Redis | 模式一 | 共享Cookie同步会话 | [文档](http://sa-token.dev33.cn/doc/index.html#/sso/sso-type1)、[示例](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-sso1) |
|
||||
| 前端不同域 + 后端同 Redis | 模式二 | URL重定向传播会话 | [文档](http://sa-token.dev33.cn/doc/index.html#/sso/sso-type2)、[示例](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-sso2-server) |
|
||||
| 前端不同域 + 后端 不同Redis | 模式三 | Http请求获取会话 | [文档](http://sa-token.dev33.cn/doc/index.html#/sso/sso-type3)、[示例](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-sso3-server) |
|
||||
|
||||
|
||||
1. 前端同域:就是指多个系统可以部署在同一个主域名之下,比如:`c1.domain.com`、`c2.domain.com`、`c3.domain.com`
|
||||
2. 后端同Redis:就是指多个系统可以连接同一个Redis,其它的缓存数据中心亦可。PS:这里并不需要把所有项目的数据都放在同一个Redis中,Sa-Token提供了 **`[权限缓存与业务缓存分离]`** 的解决方案,详情戳:[Alone独立Redis插件](http://sa-token.dev33.cn/doc/index.html#/plugin/alone-redis)
|
||||
3. 如果既无法做到前端同域,也无法做到后端同Redis,那么只能走模式三,Http请求获取会话(Sa-Token对SSO提供了完整的封装,你只需要按照示例从文档上复制几段代码便可以轻松集成)
|
||||
4. 技术选型一定要根据系统架构对症下药,切不可胡乱选择
|
||||
|
||||
|
||||
## Sa-Token-SSO 特性
|
||||
1. API简单易用,文档介绍详细,且提供直接可用的集成示例
|
||||
2. 支持三种模式,不论是否跨域、是否共享Redis,都可以完美解决
|
||||
3. 安全性高:内置域名校验、Ticket校验、秘钥校验等,杜绝`Ticket劫持`、`Token窃取`等常见攻击手段(文档讲述攻击原理和防御手段)
|
||||
4. 不丢参数:笔者曾试验多个单点登录框架,均有参数丢失的情况,比如重定向之前是:`http://a.com?id=1&name=2`,登录成功之后就变成了:`http://a.com?id=1`,Sa-Token-SSO内有专门的算法保证了参数不丢失,登录成功之后原路返回页面
|
||||
5. 无缝集成:由于Sa-Token本身就是一个权限认证框架,因此你可以只用一个框架同时解决`权限认证` + `单点登录`问题,让你不再到处搜索:xxx单点登录与xxx权限认证如何整合……
|
||||
6. 高可定制:Sa-Token-SSO模块对代码架构侵入性极低,结合Sa-Token本身的路由拦截特性,你可以非常轻松的定制化开发
|
||||
|
||||
|
||||
|
||||
## 代码示例
|
||||
|
||||
sa-token的API调用非常简单,有多简单呢?以登录验证为例,你只需要:
|
||||
Sa-Token的API调用非常简单,有多简单呢?以登录验证为例,你只需要:
|
||||
|
||||
``` java
|
||||
// 在登录时写入当前会话的账号id
|
||||
StpUtil.setLoginId(10001);
|
||||
StpUtil.login(10001);
|
||||
|
||||
// 然后在任意需要校验登录处调用以下API
|
||||
// 如果当前会话未登录,这句代码会抛出 `NotLoginException`异常
|
||||
StpUtil.checkLogin();
|
||||
```
|
||||
至此,我们已经借助sa-token框架完成登录授权!
|
||||
至此,我们已经借助Sa-Token框架完成登录授权!
|
||||
|
||||
此时的你小脑袋可能飘满了问号,就这么简单?自定义Realm呢?全局过滤器呢?我不用写各种配置文件吗?
|
||||
|
||||
事实上在此我可以负责的告诉你,在sa-token中,登录授权就是如此的简单,不需要什么全局过滤器,不需要各种乱七八糟的配置!只需要这一行简单的API调用,即可完成会话的登录授权!
|
||||
事实上在此我可以负责的告诉你,在Sa-Token中,登录授权就是如此的简单,不需要什么全局过滤器,不需要各种乱七八糟的配置!只需要这一行简单的API调用,即可完成会话的登录授权!
|
||||
|
||||
当你受够Shiro、Security等框架的三拜九叩之后,你就会明白,相对于这些传统老牌框架,sa-token的API设计是多么的清爽!
|
||||
当你受够Shiro、Spring Security等框架的三拜九叩之后,你就会明白,相对于这些传统老牌框架,Sa-Token的API设计是多么的清爽!
|
||||
|
||||
权限认证示例 (只有具有`user:add`权限的会话才可以进入请求)
|
||||
``` java
|
||||
@@ -98,9 +129,9 @@ public String insert(SysUser user) {
|
||||
StpUtil.logoutByLoginId(10001);
|
||||
```
|
||||
|
||||
除了以上的示例,sa-token还可以一行代码完成以下功能:
|
||||
除了以上的示例,Sa-Token还可以一行代码完成以下功能:
|
||||
``` java
|
||||
StpUtil.setLoginId(10001); // 标记当前会话登录的账号id
|
||||
StpUtil.login(10001); // 标记当前会话登录的账号id
|
||||
StpUtil.getLoginId(); // 获取当前会话登录的账号id
|
||||
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
|
||||
StpUtil.logout(); // 当前会话注销登录
|
||||
@@ -110,85 +141,53 @@ StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指
|
||||
StpUtil.getSession(); // 获取当前账号id的Session
|
||||
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
|
||||
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
|
||||
StpUtil.setLoginId(10001, "PC"); // 指定设备标识登录
|
||||
StpUtil.login(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的推广做一份贡献
|
||||
作者寄语:参与贡献不光只有提交代码,点一个star、提一个issues都是对开源项目的促进,
|
||||
如果Sa-Token帮助到了你,欢迎你把框架推荐给朋友、同事使用,为Sa-Token的推广做一份贡献
|
||||
|
||||
|
||||
## 建议贡献的地方
|
||||
目前框架的主要有以下部分需要大家一起参与贡献:
|
||||
- 核心代码:该部分需要开发者了解整个框架的架构,遵循已有代码规范进行bug修复或提交新功能
|
||||
- 文档部分:需要以清晰明了的语句书写文档,力求简单易读,授人以鱼同时更授人以渔
|
||||
- 社区建设:如果框架帮助到了您,希望您可以加入qq群参与交流,对不熟悉框架的新人进行排难解惑
|
||||
- 框架推广:一个优秀的开源项目不能仅靠闭门造车,它还需要一定的推广方案让更多的人一起参与到项目中
|
||||
- 其它部分:您可以参考项目issues与需求墙进行贡献
|
||||
## 使用Sa-Token的开源项目
|
||||
[**[ sa-plus ]** 一个基于springboot架构的快速开发框架,内置代码生成器](https://gitee.com/click33/sa-plus)
|
||||
|
||||
[**[ jthink ]** 一个基于springboot+sa-token+thymeleaf的博客系统](https://gitee.com/wtsoftware/jthink)
|
||||
|
||||
## 贡献者名单
|
||||
[省长](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)
|
||||
[**[ dcy-fast ]** 一个基于springboot+sa-token+mybatis-plus的后台管理系统,前端vue-element-admin,并且内置代码生成器](https://gitee.com/dcy421/dcy-fast)
|
||||
|
||||
|
||||
## 知乎专栏
|
||||
- [初识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)
|
||||
等平台连载中...欢迎投稿
|
||||
|
||||
|
||||
## 使用sa-token的开源项目
|
||||
[**[ sa-plus]** 一个基于springboot架构的快速开发框架,内置代码生成器](https://gitee.com/sz6/sa-plus)
|
||||
|
||||
如果您的项目使用了sa-token,欢迎提交pr
|
||||
如果您的项目使用了Sa-Token,欢迎提交pr
|
||||
|
||||
|
||||
## 友情链接
|
||||
[**[ 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)
|
||||
|
||||

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

|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
:: 整体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-solon
|
||||
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 sa-token-demo-alone-redis
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-sso1
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-sso2-server
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-sso2-client
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-sso3-server
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-sso3-client
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cd ..
|
||||
|
||||
:: 最后打印
|
||||
echo;
|
||||
echo;
|
||||
echo ----------- clean end -----------
|
||||
echo;
|
||||
pause
|
||||
@@ -8,22 +8,20 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.14.0</version>
|
||||
<version>1.21.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-solon</module> -->
|
||||
</modules>
|
||||
|
||||
<!-- 开源协议 apache 2.0 -->
|
||||
@@ -38,7 +36,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.21.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.21.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>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
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.temp.SaTempInterface;
|
||||
import cn.dev33.satoken.temp.SaTempDefaultImpl;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 管理 Sa-Token 所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaManager {
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
public static SaTokenConfig config;
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaManager.config = config;
|
||||
if(config.getIsPrint()) {
|
||||
SaFoxUtil.printSaToken();
|
||||
}
|
||||
// 调用一次StpUtil中的方法,保证其可以尽早的初始化 StpLogic
|
||||
StpUtil.getLoginType();
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时令牌验证模块 Bean
|
||||
*/
|
||||
private static SaTempInterface saTemp;
|
||||
public static void setSaTemp(SaTempInterface saTemp) {
|
||||
SaManager.saTemp = saTemp;
|
||||
}
|
||||
public static SaTempInterface getSaTemp() {
|
||||
if (saTemp == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTemp == null) {
|
||||
setSaTemp(new SaTempDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.getLoginType(), stpLogic);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 LoginType 获取对应的StpLogic,如果不存在则抛出异常
|
||||
* @param loginType 对应的账号类型
|
||||
* @return 对应的StpLogic
|
||||
*/
|
||||
public static StpLogic getStpLogic(String loginType) {
|
||||
// 如果type为空则返回框架内置的
|
||||
if(loginType == null || loginType.isEmpty()) {
|
||||
return StpUtil.stpLogic;
|
||||
}
|
||||
|
||||
// 从SaManager中获取
|
||||
StpLogic stpLogic = stpLogicMap.get(loginType);
|
||||
if(stpLogic == null) {
|
||||
/*
|
||||
* 此时有两种情况会造成 StpLogic == null
|
||||
* 1. loginType拼写错误,请改正 (建议使用常量)
|
||||
* 2. 自定义StpUtil尚未初始化(静态类中的属性至少一次调用后才会初始化),解决方法两种
|
||||
* (1) 从main方法里调用一次
|
||||
* (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
|
||||
*/
|
||||
throw new SaTokenException("未能获取对应StpLogic,type="+ loginType);
|
||||
}
|
||||
|
||||
// 返回
|
||||
return stpLogic;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
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.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenManager {
|
||||
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
private static SaTokenConfig config;
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
initConfig();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaTokenManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaTokenInsideUtil.printSaToken();
|
||||
}
|
||||
}
|
||||
public synchronized static void initConfig() {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 持久化 Bean
|
||||
*/
|
||||
public static SaTokenDao saTokenDao;
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
initSaTokenDao();
|
||||
}
|
||||
return saTokenDao;
|
||||
}
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshTimer();
|
||||
}
|
||||
SaTokenManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public synchronized static void initSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限认证 Bean
|
||||
*/
|
||||
public static StpInterface stpInterface;
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
initStpInterface();
|
||||
}
|
||||
return stpInterface;
|
||||
}
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaTokenManager.stpInterface = stpInterface;
|
||||
}
|
||||
public synchronized static void initStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 框架行为 Bean
|
||||
*/
|
||||
public static SaTokenAction saTokenAction;
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
initSaTokenAction();
|
||||
}
|
||||
return saTokenAction;
|
||||
}
|
||||
public static void setSaTokenAction(SaTokenAction saTokenAction) {
|
||||
SaTokenManager.saTokenAction = saTokenAction;
|
||||
}
|
||||
public synchronized static void initSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie操作 Bean
|
||||
*/
|
||||
public static SaTokenCookie saTokenCookie;
|
||||
public static SaTokenCookie getSaTokenCookie() {
|
||||
if (saTokenCookie == null) {
|
||||
initSaTokenCookie();
|
||||
}
|
||||
return saTokenCookie;
|
||||
}
|
||||
public static void setSaTokenCookie(SaTokenCookie saTokenCookie) {
|
||||
SaTokenManager.saTokenCookie = saTokenCookie;
|
||||
}
|
||||
public synchronized static void initSaTokenCookie() {
|
||||
if (saTokenCookie == null) {
|
||||
setSaTokenCookie(new SaTokenCookieDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet操作 Bean
|
||||
*/
|
||||
public static SaTokenServlet saTokenServlet;
|
||||
public static SaTokenServlet getSaTokenServlet() {
|
||||
if (saTokenServlet == null) {
|
||||
initSaTokenServlet();
|
||||
}
|
||||
return saTokenServlet;
|
||||
}
|
||||
public static void setSaTokenServlet(SaTokenServlet saTokenServlet) {
|
||||
SaTokenManager.saTokenServlet = saTokenServlet;
|
||||
}
|
||||
public synchronized static void initSaTokenServlet() {
|
||||
if (saTokenServlet == null) {
|
||||
setSaTokenServlet(new SaTokenServletDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token逻辑代理接口
|
||||
* Sa-Token 逻辑代理接口
|
||||
* <p>此接口将会代理框架内部的一些关键性逻辑,方便开发者进行按需重写</p>
|
||||
* @author kong
|
||||
*
|
||||
@@ -11,18 +14,32 @@ import cn.dev33.satoken.session.SaSession;
|
||||
public interface SaTokenAction {
|
||||
|
||||
/**
|
||||
* 根据一定的算法生成一个token
|
||||
* 创建一个Token
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 账号体系key
|
||||
* @return 一个token
|
||||
* @param loginType 账号类型
|
||||
* @return token
|
||||
*/
|
||||
public String createToken(Object loginId, String loginKey);
|
||||
public String createToken(Object loginId, String loginType);
|
||||
|
||||
/**
|
||||
* 根据 SessionId 创建一个 Session
|
||||
* 创建一个Session
|
||||
* @param sessionId Session的Id
|
||||
* @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,27 +1,33 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
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.annotation.SaCheckSafe;
|
||||
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 接口的默认实现
|
||||
* Sa-Token 逻辑代理接口 [默认实现类]
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenActionDefaultImpl implements SaTokenAction {
|
||||
|
||||
|
||||
/**
|
||||
* 根据一定的算法生成一个token
|
||||
* 创建一个Token
|
||||
*/
|
||||
@Override
|
||||
public String createToken(Object loginId, String loginKey) {
|
||||
public String createToken(Object loginId, String loginType) {
|
||||
// 根据配置的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,31 +38,101 @@ 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
|
||||
* 创建一个Session
|
||||
*/
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
// 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配
|
||||
if (list.contains(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 开始模糊匹配
|
||||
for (String patt : list) {
|
||||
if(SaFoxUtil.vagueMatch(patt, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 走出for循环说明没有一个元素可以匹配成功
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解检查(注解鉴权内部实现)
|
||||
*/
|
||||
@Override
|
||||
public void checkMethodAnnotation(Method method) {
|
||||
|
||||
// 先校验 Method 所属 Class 上的注解
|
||||
validateAnnotation(method.getDeclaringClass());
|
||||
|
||||
// 再校验 Method 上的注解
|
||||
validateAnnotation(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定元素校验注解
|
||||
* @param target see note
|
||||
*/
|
||||
protected void validateAnnotation(AnnotatedElement target) {
|
||||
|
||||
// 校验 @SaCheckLogin 注解
|
||||
if(target.isAnnotationPresent(SaCheckLogin.class)) {
|
||||
SaCheckLogin at = target.getAnnotation(SaCheckLogin.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckRole 注解
|
||||
if(target.isAnnotationPresent(SaCheckRole.class)) {
|
||||
SaCheckRole at = target.getAnnotation(SaCheckRole.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckPermission 注解
|
||||
if(target.isAnnotationPresent(SaCheckPermission.class)) {
|
||||
SaCheckPermission at = target.getAnnotation(SaCheckPermission.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 校验 @SaCheckSafe 注解
|
||||
if(target.isAnnotationPresent(SaCheckSafe.class)) {
|
||||
SaCheckSafe at = target.getAnnotation(SaCheckSafe.class);
|
||||
SaManager.getStpLogic(null).checkByAnnotation(at);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 登录校验:标注在一个方法上,当前会话必须已经登录才能进入该方法
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* 登录认证:只有登录之后才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -15,4 +15,10 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaCheckLogin {
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String type() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 权限校验:标注在一个方法上,当前会话必须具有指定权限才能进入该方法
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* 权限认证:必须具有指定权限才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -26,5 +26,11 @@ public @interface SaCheckPermission {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String type() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 角色校验:标注在一个方法上,当前会话必须具有指定角色标识才能进入该方法
|
||||
* <p> 可标注在类上,其效果等同于标注在此类的所有方法上
|
||||
* 角色认证:必须具有指定角色标识才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -26,5 +26,12 @@ public @interface SaCheckRole {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
/**
|
||||
* 账号类型
|
||||
* <p> 建议使用常量,避免因错误拼写带来的bug
|
||||
* @return see note
|
||||
*/
|
||||
String type() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.dev33.satoken.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 二级认证校验:必须二级认证之后才能进入该方法
|
||||
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaCheckSafe {
|
||||
|
||||
}
|
||||
@@ -8,12 +8,12 @@ package cn.dev33.satoken.annotation;
|
||||
public enum SaMode {
|
||||
|
||||
/**
|
||||
* 必须具有所有的选项
|
||||
* 必须具有所有的元素
|
||||
*/
|
||||
AND,
|
||||
|
||||
/**
|
||||
* 只需具有其中一个选项
|
||||
* 只需具有其中一个元素
|
||||
*/
|
||||
OR
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO 单点登录模块 配置Model
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSsoConfig {
|
||||
|
||||
/**
|
||||
* Ticket有效期 (单位: 秒)
|
||||
*/
|
||||
public long ticketTimeout = 60 * 5;
|
||||
|
||||
/**
|
||||
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
*/
|
||||
public String allowUrl = "*";
|
||||
|
||||
/**
|
||||
* 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
*/
|
||||
public String secretkey;
|
||||
|
||||
/**
|
||||
* SSO-Server端 单点登录地址
|
||||
*/
|
||||
public String authUrl;
|
||||
|
||||
/**
|
||||
* SSO-Server端 Ticket校验地址
|
||||
*/
|
||||
public String checkTicketUrl;
|
||||
|
||||
/**
|
||||
* SSO-Server端 单点注销地址
|
||||
*/
|
||||
public String sloUrl;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Ticket有效期 (单位: 秒)
|
||||
*/
|
||||
public long getTicketTimeout() {
|
||||
return ticketTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ticketTimeout Ticket有效期 (单位: 秒)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setTicketTimeout(long ticketTimeout) {
|
||||
this.ticketTimeout = ticketTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
*/
|
||||
public String getAllowUrl() {
|
||||
return allowUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowUrl 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setAllowUrl(String allowUrl) {
|
||||
this.allowUrl = allowUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
*/
|
||||
public String getSecretkey() {
|
||||
return secretkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param secretkey 调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setSecretkey(String secretkey) {
|
||||
this.secretkey = secretkey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SSO-Server端 单点登录地址
|
||||
*/
|
||||
public String getAuthUrl() {
|
||||
return authUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authUrl SSO-Server端 单点登录地址
|
||||
*/
|
||||
public void setAuthUrl(String authUrl) {
|
||||
this.authUrl = authUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SSO-Server端Ticket校验地址
|
||||
*/
|
||||
public String getCheckTicketUrl() {
|
||||
return checkTicketUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checkTicketUrl SSO-Server端Ticket校验地址
|
||||
*/
|
||||
public void setCheckTicketUrl(String checkTicketUrl) {
|
||||
this.checkTicketUrl = checkTicketUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SSO-Server端单点注销地址
|
||||
*/
|
||||
public String getSloUrl() {
|
||||
return sloUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sloUrl SSO-Server端单点注销地址
|
||||
*/
|
||||
public void setSloUrl(String sloUrl) {
|
||||
this.sloUrl = sloUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaSsoConfig [ticketTimeout=" + ticketTimeout + ", allowUrl=" + allowUrl + ", secretkey=" + secretkey
|
||||
+ ", authUrl=" + authUrl + ", checkTicketUrl=" + checkTicketUrl + ", sloUrl=" + sloUrl + "]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 以数组形式写入允许的授权回调地址
|
||||
* @param url 所有集合
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaSsoConfig setAllow(String ...url) {
|
||||
this.allowUrl = SaFoxUtil.arrayJoin(url);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
/**
|
||||
* sa-token 配置类 Model
|
||||
* Sa-Token 配置类 Model
|
||||
* <p>
|
||||
* 你可以通过yml、properties、java代码等形式配置本类参数,具体请查阅官方文档: http://sa-token.dev33.cn/
|
||||
*
|
||||
@@ -23,7 +23,7 @@ public class SaTokenConfig {
|
||||
private long activityTimeout = -1;
|
||||
|
||||
/** 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) */
|
||||
private Boolean allowConcurrentLogin = true;
|
||||
private Boolean isConcurrent = true;
|
||||
|
||||
/** 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) */
|
||||
private Boolean isShare = true;
|
||||
@@ -51,10 +51,25 @@ public class SaTokenConfig {
|
||||
|
||||
/** 写入Cookie时显式指定的作用域, 常用于单点登录二级域名共享Cookie的场景 */
|
||||
private String cookieDomain;
|
||||
|
||||
/** token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx) */
|
||||
private String tokenPrefix;
|
||||
|
||||
/** 是否在初始化配置时打印版本字符画 */
|
||||
private Boolean isV = true;
|
||||
private Boolean isPrint = true;
|
||||
|
||||
/** 是否打印操作日志 */
|
||||
private Boolean isLog = false;
|
||||
|
||||
/**
|
||||
* jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效)
|
||||
*/
|
||||
private String jwtSecretKey;
|
||||
|
||||
/**
|
||||
* SSO单点登录配置对象
|
||||
*/
|
||||
public SaSsoConfig sso = new SaSsoConfig();
|
||||
|
||||
|
||||
/**
|
||||
@@ -108,18 +123,18 @@ public class SaTokenConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
* @return 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
*/
|
||||
public Boolean getAllowConcurrentLogin() {
|
||||
return allowConcurrentLogin;
|
||||
public Boolean getIsConcurrent() {
|
||||
return isConcurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowConcurrentLogin 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
* @param isConcurrent 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setAllowConcurrentLogin(Boolean allowConcurrentLogin) {
|
||||
this.allowConcurrentLogin = allowConcurrentLogin;
|
||||
public SaTokenConfig setIsConcurrent(Boolean isConcurrent) {
|
||||
this.isConcurrent = isConcurrent;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -270,36 +285,122 @@ public class SaTokenConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否在初始化配置时打印版本字符画
|
||||
* @return token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
|
||||
*/
|
||||
public Boolean getIsV() {
|
||||
return isV;
|
||||
public String getTokenPrefix() {
|
||||
return tokenPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isV 是否在初始化配置时打印版本字符画
|
||||
* @param tokenPrefix token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setIsV(Boolean isV) {
|
||||
this.isV = isV;
|
||||
public SaTokenConfig setTokenPrefix(String tokenPrefix) {
|
||||
this.tokenPrefix = tokenPrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否在初始化配置时打印版本字符画
|
||||
*/
|
||||
public Boolean getIsPrint() {
|
||||
return isPrint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isPrint 是否在初始化配置时打印版本字符画
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setIsPrint(Boolean isPrint) {
|
||||
this.isPrint = isPrint;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否打印操作日志
|
||||
*/
|
||||
public Boolean getIsLog() {
|
||||
return isLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString
|
||||
* @param isLog 是否打印操作日志
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setIsLog(Boolean isLog) {
|
||||
this.isLog = isLog;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效)
|
||||
*/
|
||||
public String getJwtSecretKey() {
|
||||
return jwtSecretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwtSecretKey jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效)
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaTokenConfig setJwtSecretKey(String jwtSecretKey) {
|
||||
this.jwtSecretKey = jwtSecretKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SSO单点登录配置对象
|
||||
*/
|
||||
public SaSsoConfig getSso() {
|
||||
return sso;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param sso SSO单点登录配置对象
|
||||
*/
|
||||
public void setSso(SaSsoConfig sso) {
|
||||
this.sso = sso;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenConfig [tokenName=" + tokenName + ", timeout=" + timeout + ", activityTimeout=" + activityTimeout
|
||||
+ ", allowConcurrentLogin=" + allowConcurrentLogin + ", isShare=" + isShare + ", isReadBody="
|
||||
+ ", isConcurrent=" + isConcurrent + ", isShare=" + isShare + ", isReadBody="
|
||||
+ isReadBody + ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle="
|
||||
+ tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin="
|
||||
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain + ", isV="
|
||||
+ isV + "]";
|
||||
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain
|
||||
+ ", tokenPrefix=" + tokenPrefix + ", isPrint=" + isPrint + ", isLog=" + isLog + ", jwtSecretKey="
|
||||
+ jwtSecretKey + ", sso=" + sso + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 setIsConcurrent() ,使用方式保持不变 </h1>
|
||||
* @param allowConcurrentLogin see note
|
||||
* @return see note
|
||||
*/
|
||||
@Deprecated
|
||||
public SaTokenConfig setAllowConcurrentLogin(Boolean allowConcurrentLogin) {
|
||||
this.isConcurrent = allowConcurrentLogin;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 setIsConcurrent() ,使用方式保持不变 </h1>
|
||||
* @param isV see note
|
||||
* @return see note
|
||||
*/
|
||||
public SaTokenConfig setIsV(Boolean isV) {
|
||||
this.isPrint = isV;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* sa-token配置文件的构建工厂类
|
||||
* Sa-Token配置文件的构建工厂类
|
||||
* <p>
|
||||
* 只有在非IOC环境下才会用到此类
|
||||
*
|
||||
@@ -94,9 +94,7 @@ public class SaTokenConfigFactory {
|
||||
Object valueConvert = getObjectByClass(value, field.getType());
|
||||
field.setAccessible(true);
|
||||
field.set(obj, valueConvert);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("属性赋值出错:" + field.getName(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("属性赋值出错:" + field.getName(), e);
|
||||
}
|
||||
}
|
||||
@@ -112,23 +110,23 @@ public class SaTokenConfigFactory {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getObjectByClass(String str, Class<T> cs) {
|
||||
Object value = null;
|
||||
Object value;
|
||||
if (str == null) {
|
||||
value = null;
|
||||
} else if (cs.equals(String.class)) {
|
||||
value = str;
|
||||
} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
|
||||
value = new Integer(str);
|
||||
value = Integer.valueOf(str);
|
||||
} else if (cs.equals(long.class) || cs.equals(Long.class)) {
|
||||
value = new Long(str);
|
||||
value = Long.valueOf(str);
|
||||
} else if (cs.equals(short.class) || cs.equals(Short.class)) {
|
||||
value = new Short(str);
|
||||
value = Short.valueOf(str);
|
||||
} else if (cs.equals(float.class) || cs.equals(Float.class)) {
|
||||
value = new Float(str);
|
||||
value = Float.valueOf(str);
|
||||
} else if (cs.equals(double.class) || cs.equals(Double.class)) {
|
||||
value = new Double(str);
|
||||
value = Double.valueOf(str);
|
||||
} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
|
||||
value = new Boolean(str);
|
||||
value = Boolean.valueOf(str);
|
||||
} else {
|
||||
throw new RuntimeException("未能将值:" + str + ",转换类型为:" + cs, null);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+34
@@ -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;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [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;
|
||||
}
|
||||
|
||||
}
|
||||
+139
@@ -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;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [ThreadLocal版本] ---- 对象存储器
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextForThreadLocalStorage {
|
||||
|
||||
/**
|
||||
* 基于 ThreadLocal 的 [Box存储器]
|
||||
*/
|
||||
public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<Box>();
|
||||
|
||||
/**
|
||||
* 初始化 [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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 清除 [Box存储器]
|
||||
*/
|
||||
public static void clearBox() {
|
||||
boxThreadLocal.remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 [Box存储器]
|
||||
* @return see note
|
||||
*/
|
||||
public static Box getBox() {
|
||||
return boxThreadLocal.get();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 [Box存储器], 如果为空则抛出异常
|
||||
* @return see note
|
||||
*/
|
||||
public static Box getBoxNotNull() {
|
||||
Box box = boxThreadLocal.get();
|
||||
if(box == null) {
|
||||
throw new SaTokenException("未成功初始化上下文");
|
||||
}
|
||||
return box;
|
||||
};
|
||||
|
||||
/**
|
||||
* 在 [Box存储器] 获取 [Request] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaRequest getRequest() {
|
||||
return getBoxNotNull().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 [Box存储器] 获取 [Response] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaResponse getResponse() {
|
||||
return getBoxNotNull().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 [Box存储器] 获取 [存储器] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaStorage getStorage() {
|
||||
return getBoxNotNull().getStorage();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 临时内部类,用于存储[request、response、storage]三个对象
|
||||
* @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,55 @@
|
||||
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();
|
||||
|
||||
/**
|
||||
* 返回当前请求的url,例:http://xxx.com/?id=127
|
||||
* @return see note
|
||||
*/
|
||||
public String getUrl();
|
||||
|
||||
/**
|
||||
* 返回当前请求的类型
|
||||
* @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) == false) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,113 +5,113 @@ import java.util.List;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的接口
|
||||
* Sa-Token持久层接口
|
||||
* @author kong
|
||||
*/
|
||||
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相关 ---------------------
|
||||
// --------------------- 字符串读写 ---------------------
|
||||
|
||||
/**
|
||||
* 根据key获取value,如果没有,则返回空
|
||||
* 获取Value,如无返空
|
||||
* @param key 键名称
|
||||
* @return value
|
||||
*/
|
||||
public String get(String key);
|
||||
|
||||
/**
|
||||
* 写入指定key-value键值对,并设定过期时间 (单位: 秒)
|
||||
* 写入Value,并设定存活时间 (单位: 秒)
|
||||
* @param key 键名称
|
||||
* @param value 值
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void set(String key, String value, long timeout);
|
||||
|
||||
/**
|
||||
* 修改指定key-value键值对 (过期时间不变)
|
||||
* 更新Value (过期时间不变)
|
||||
* @param key 键名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void update(String key, String value);
|
||||
|
||||
/**
|
||||
* 删除一个指定的key
|
||||
* 删除Value
|
||||
* @param key 键名称
|
||||
*/
|
||||
public void delete(String key);
|
||||
|
||||
/**
|
||||
* 获取指定key的剩余存活时间 (单位: 秒)
|
||||
* 获取Value的剩余存活时间 (单位: 秒)
|
||||
* @param key 指定key
|
||||
* @return 这个key的剩余存活时间
|
||||
*/
|
||||
public long getTimeout(String key);
|
||||
|
||||
/**
|
||||
* 修改指定key的剩余存活时间 (单位: 秒)
|
||||
* 修改Value的剩余存活时间 (单位: 秒)
|
||||
* @param key 指定key
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void updateTimeout(String key, long timeout);
|
||||
|
||||
|
||||
// --------------------- Object相关 ---------------------
|
||||
// --------------------- 对象读写 ---------------------
|
||||
|
||||
/**
|
||||
* 根据key获取Object,如果没有,则返回空
|
||||
* 获取Object,如无返空
|
||||
* @param key 键名称
|
||||
* @return object
|
||||
*/
|
||||
public Object getObject(String key);
|
||||
|
||||
/**
|
||||
* 写入指定键值对,并设定过期时间 (单位: 秒)
|
||||
* 写入Object,并设定存活时间 (单位: 秒)
|
||||
* @param key 键名称
|
||||
* @param object 值
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
* @param timeout 存活时间
|
||||
*/
|
||||
public void setObject(String key, Object object, long timeout);
|
||||
|
||||
/**
|
||||
* 修改指定键值对 (过期时间不变)
|
||||
* 更新Object (过期时间不变)
|
||||
* @param key 键名称
|
||||
* @param object 值
|
||||
*/
|
||||
public void updateObject(String key, Object object);
|
||||
|
||||
/**
|
||||
* 删除一个指定的Object
|
||||
* 删除Object
|
||||
* @param key 键名称
|
||||
*/
|
||||
public void deleteObject(String key);
|
||||
|
||||
/**
|
||||
* 获取指定key的剩余存活时间 (单位: 秒)
|
||||
* 获取Object的剩余存活时间 (单位: 秒)
|
||||
* @param key 指定key
|
||||
* @return 这个key的剩余存活时间
|
||||
*/
|
||||
public long getObjectTimeout(String key);
|
||||
|
||||
/**
|
||||
* 修改指定key的剩余存活时间 (单位: 秒)
|
||||
* 修改Object的剩余存活时间 (单位: 秒)
|
||||
* @param key 指定key
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void updateObjectTimeout(String key, long timeout);
|
||||
|
||||
|
||||
// --------------------- Session相关 ---------------------
|
||||
// --------------------- Session读写 ---------------------
|
||||
|
||||
/**
|
||||
* 根据指定key的Session,如果没有,则返回空
|
||||
* @param sessionId 键名称
|
||||
* 获取Session,如无返空
|
||||
* @param sessionId sessionId
|
||||
* @return SaSession
|
||||
*/
|
||||
public default SaSession getSession(String sessionId) {
|
||||
@@ -119,8 +119,8 @@ public interface SaTokenDao {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定Session持久化
|
||||
* @param session 要保存的session对象
|
||||
* 写入Session,并设定存活时间 (单位: 秒)
|
||||
* @param session 要保存的Session对象
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public default void setSession(SaSession session, long timeout) {
|
||||
@@ -128,7 +128,7 @@ public interface SaTokenDao {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指定session
|
||||
* 更新Session
|
||||
* @param session 要更新的session对象
|
||||
*/
|
||||
public default void updateSession(SaSession session) {
|
||||
@@ -136,7 +136,7 @@ public interface SaTokenDao {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个指定的session
|
||||
* 删除Session
|
||||
* @param sessionId sessionId
|
||||
*/
|
||||
public default void deleteSession(String sessionId) {
|
||||
@@ -144,17 +144,17 @@ public interface SaTokenDao {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定SaSession的剩余存活时间 (单位: 秒)
|
||||
* @param sessionId 指定SaSession
|
||||
* @return 这个SaSession的剩余存活时间 (单位: 秒)
|
||||
* 获取Session剩余存活时间 (单位: 秒)
|
||||
* @param sessionId 指定Session
|
||||
* @return 这个Session的剩余存活时间
|
||||
*/
|
||||
public default long getSessionTimeout(String sessionId) {
|
||||
return getObjectTimeout(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改指定SaSession的剩余存活时间 (单位: 秒)
|
||||
* @param sessionId sessionId
|
||||
* 修改Session剩余存活时间 (单位: 秒)
|
||||
* @param sessionId 指定Session
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public default void updateSessionTimeout(String sessionId, long timeout) {
|
||||
|
||||
@@ -4,16 +4,13 @@ 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
|
||||
* Sa-Token持久层接口 [默认实现类, 基于内存Map]
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -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,29 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表停止匹配,直接退出,向前端输出结果
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class BackResultException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130143L;
|
||||
|
||||
/**
|
||||
* 要输出的结果
|
||||
*/
|
||||
public Object result;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param result 要输出的结果
|
||||
*/
|
||||
public BackResultException(Object result) {
|
||||
super(String.valueOf(result));
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
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 = "此账号已被封禁";
|
||||
|
||||
/**
|
||||
* 账号类型
|
||||
*/
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 被封禁的账号id
|
||||
*/
|
||||
private Object loginId;
|
||||
|
||||
/**
|
||||
* 封禁剩余时间,单位:秒
|
||||
*/
|
||||
private long disableTime;
|
||||
|
||||
/**
|
||||
* 获取账号类型
|
||||
*
|
||||
* @return See Note
|
||||
*/
|
||||
public String getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取: 被封禁的账号id
|
||||
*
|
||||
* @return See above
|
||||
*/
|
||||
public Object getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取: 封禁剩余时间,单位:秒
|
||||
* @return See above
|
||||
*/
|
||||
public long getDisableTime() {
|
||||
return disableTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表账号已被封禁
|
||||
*
|
||||
* @param loginType 账号类型
|
||||
* @param loginId 被封禁的账号id
|
||||
* @param disableTime 封禁剩余时间,单位:秒
|
||||
*/
|
||||
public DisableLoginException(String loginType, Object loginId, long disableTime) {
|
||||
super(BE_MESSAGE);
|
||||
this.loginId = loginId;
|
||||
this.loginType = loginType;
|
||||
this.disableTime = disableTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 一个异常:代表用户没有登录
|
||||
* 一个异常:代表会话未能通过登录认证
|
||||
* @author kong
|
||||
*/
|
||||
public class NotLoginException extends SaTokenException {
|
||||
@@ -67,38 +67,38 @@ public class NotLoginException extends SaTokenException {
|
||||
|
||||
|
||||
/**
|
||||
* loginKey
|
||||
* 账号类型
|
||||
*/
|
||||
private String loginKey;
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 获得loginKey
|
||||
* @return loginKey
|
||||
* 获得账号类型
|
||||
* @return 账号类型
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
public String getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构造方法创建一个
|
||||
* @param message 异常消息
|
||||
* @param loginKey loginKey
|
||||
* @param loginType 账号类型
|
||||
* @param type 类型
|
||||
*/
|
||||
public NotLoginException(String message, String loginKey, String type) {
|
||||
public NotLoginException(String message, String loginType, String type) {
|
||||
super(message);
|
||||
this.loginKey = loginKey;
|
||||
this.loginType = loginType;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态方法构建一个NotLoginException
|
||||
* @param loginKey loginKey
|
||||
* @param type 场景类型
|
||||
* @param loginType 账号类型
|
||||
* @param type 账号类型
|
||||
* @return 构建完毕的异常对象
|
||||
*/
|
||||
public static NotLoginException newInstance(String loginKey, String type) {
|
||||
public static NotLoginException newInstance(String loginType, String type) {
|
||||
String message = null;
|
||||
if(NOT_TOKEN.equals(type)) {
|
||||
message = NOT_TOKEN_MESSAGE;
|
||||
@@ -118,7 +118,7 @@ public class NotLoginException extends SaTokenException {
|
||||
else {
|
||||
message = DEFAULT_MESSAGE;
|
||||
}
|
||||
return new NotLoginException(message, loginKey, type);
|
||||
return new NotLoginException(message, loginType, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-11
@@ -3,7 +3,7 @@ package cn.dev33.satoken.exception;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* 没有指定权限码,抛出的异常
|
||||
* 一个异常:代表会话未能通过权限认证
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
@@ -13,7 +13,7 @@ public class NotPermissionException extends SaTokenException {
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
private static final long serialVersionUID = 6806129545290130141L;
|
||||
|
||||
/** 权限码 */
|
||||
private String code;
|
||||
@@ -26,27 +26,27 @@ public class NotPermissionException extends SaTokenException {
|
||||
}
|
||||
|
||||
/**
|
||||
* loginKey
|
||||
* 账号类型
|
||||
*/
|
||||
private String loginKey;
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 获得loginKey
|
||||
* 获得账号类型
|
||||
*
|
||||
* @return loginKey
|
||||
* @return 账号类型
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
public String getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
public NotPermissionException(String code) {
|
||||
this(code, StpUtil.stpLogic.loginKey);
|
||||
this(code, StpUtil.stpLogic.loginType);
|
||||
}
|
||||
|
||||
public NotPermissionException(String code, String loginKey) {
|
||||
public NotPermissionException(String code, String loginType) {
|
||||
super("无此权限:" + code);
|
||||
this.code = code;
|
||||
this.loginKey = loginKey;
|
||||
this.loginType = loginType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package cn.dev33.satoken.exception;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* 没有指定角色标识,抛出的异常
|
||||
* 一个异常:代表会话未能通过角色认证
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
@@ -26,28 +26,27 @@ public class NotRoleException extends SaTokenException {
|
||||
}
|
||||
|
||||
/**
|
||||
* loginKey
|
||||
* 账号类型
|
||||
*/
|
||||
private String loginKey;
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 获得loginKey
|
||||
* 获得账号类型
|
||||
*
|
||||
* @return loginKey
|
||||
* @return 账号类型
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
public String getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
public NotRoleException(String role) {
|
||||
this(role, StpUtil.stpLogic.loginKey);
|
||||
this(role, StpUtil.stpLogic.loginType);
|
||||
}
|
||||
|
||||
public NotRoleException(String role, String loginKey) {
|
||||
// 这里到底要不要拼接上loginKey呢?纠结
|
||||
public NotRoleException(String role, String loginType) {
|
||||
super("无此角色:" + role);
|
||||
this.role = role;
|
||||
this.loginKey = loginKey;
|
||||
this.loginType = loginType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表会话未能通过二级认证
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class NotSafeException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130144L;
|
||||
|
||||
/** 异常提示语 */
|
||||
public static final String BE_MESSAGE = "二级认证失败";
|
||||
|
||||
/**
|
||||
* 一个异常:代表会话未通过二级认证
|
||||
*/
|
||||
public NotSafeException() {
|
||||
super(BE_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* sa-token框架内部逻辑发生错误抛出的异常
|
||||
* (自定义此异常可方便开发者在做全局异常处理时分辨异常类型)
|
||||
* Sa-Token框架内部逻辑发生错误抛出的异常
|
||||
* (自定义此异常方便开发者在做全局异常处理时分辨异常类型)
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表停止路由匹配
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class StopMatchException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130143L;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public StopMatchException() {
|
||||
super("stop match");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.dev33.satoken.fun;
|
||||
|
||||
/**
|
||||
* 根据boolean变量,决定是否执行一个函数
|
||||
* 根据Boolean变量,决定是否执行一个函数
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@ package cn.dev33.satoken.fun;
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaFunction {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.dev33.satoken.fun;
|
||||
|
||||
/**
|
||||
* 设定一个函数,并返回一个值,方便在Lambda表达式下的函数式编程
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaRetFunction {
|
||||
|
||||
/**
|
||||
* 执行的方法
|
||||
* @return 返回值
|
||||
*/
|
||||
public Object run();
|
||||
|
||||
}
|
||||
@@ -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 loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param loginModel 登录参数
|
||||
*/
|
||||
public void doLogin(String loginType, Object loginId, SaLoginModel loginModel);
|
||||
|
||||
/**
|
||||
* 每次注销时触发
|
||||
* @param loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
*/
|
||||
public void doLogout(String loginType, Object loginId, String tokenValue);
|
||||
|
||||
/**
|
||||
* 每次被踢下线时触发
|
||||
* @param loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public void doLogoutByLoginId(String loginType, Object loginId, String tokenValue, String device);
|
||||
|
||||
/**
|
||||
* 每次被顶下线时触发
|
||||
* @param loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param tokenValue token值
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public void doReplaced(String loginType, Object loginId, String tokenValue, String device);
|
||||
|
||||
/**
|
||||
* 每次被封禁时触发
|
||||
* @param loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
* @param disableTime 封禁时长,单位: 秒
|
||||
*/
|
||||
public void doDisable(String loginType, Object loginId, long disableTime);
|
||||
|
||||
/**
|
||||
* 每次被解封时触发
|
||||
* @param loginType 账号类别
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void doUntieDisable(String loginType, 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 loginType, Object loginId, SaLoginModel loginModel) {
|
||||
println("账号[" + loginId + "]登录成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次注销时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogout(String loginType, Object loginId, String tokenValue) {
|
||||
println("账号[" + loginId + "]注销成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被踢下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogoutByLoginId(String loginType, Object loginId, String tokenValue, String device) {
|
||||
println("账号[" + loginId + "]被踢下线 (终端: " + device + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被顶下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doReplaced(String loginType, Object loginId, String tokenValue, String device) {
|
||||
println("账号[" + loginId + "]被顶下线 (终端: " + device + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被封禁时触发
|
||||
*/
|
||||
@Override
|
||||
public void doDisable(String loginType, Object loginId, long disableTime) {
|
||||
Date date = new Date(System.currentTimeMillis() + disableTime * 1000);
|
||||
println("账号[" + loginId + "]被封禁 (解封时间: " + SaFoxUtil.formatDate(date) + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被解封时触发
|
||||
*/
|
||||
@Override
|
||||
public void doUntieDisable(String loginType, 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;
|
||||
|
||||
/**
|
||||
* 路由拦截器验证方法Lambda
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaRouteFunction {
|
||||
|
||||
/**
|
||||
* 执行验证的方法
|
||||
*
|
||||
* @param request Request包装对象
|
||||
* @param response Response包装对象
|
||||
* @param handler 处理对象
|
||||
*/
|
||||
public void run(SaRequest request, SaResponse response, Object handler);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package cn.dev33.satoken.router;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.exception.BackResultException;
|
||||
import cn.dev33.satoken.exception.StopMatchException;
|
||||
import cn.dev33.satoken.fun.IsRunFunction;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
|
||||
/**
|
||||
* 路由匹配操作工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaRouter {
|
||||
|
||||
// -------------------- 路由匹配相关 --------------------
|
||||
|
||||
/**
|
||||
* 路由匹配
|
||||
* @param pattern 路由匹配符
|
||||
* @param path 被匹配的路由
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String path) {
|
||||
return SaManager.getSaTokenContext().matchPath(pattern, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配
|
||||
* @param patterns 路由匹配符集合
|
||||
* @param path 被匹配的路由
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatch(List<String> patterns, String path) {
|
||||
for (String pattern : patterns) {
|
||||
if(isMatch(pattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配 (使用当前URI)
|
||||
* @param pattern 路由匹配符
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(String pattern) {
|
||||
return isMatch(pattern, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配 (使用当前URI)
|
||||
* @param patterns 路由匹配符集合
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(List<String> patterns) {
|
||||
return isMatch(patterns, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 执行相关 --------------------
|
||||
|
||||
/**
|
||||
* 路由匹配,如果匹配成功则执行认证函数
|
||||
* @param pattern 路由匹配符
|
||||
* @param function 要执行的方法
|
||||
*/
|
||||
public static void match(String pattern, SaFunction function) {
|
||||
if(isMatchCurrURI(pattern)) {
|
||||
function.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配 (并指定排除匹配符),如果匹配成功则执行认证函数
|
||||
* @param pattern 路由匹配符
|
||||
* @param excludePattern 要排除的路由匹配符
|
||||
* @param function 要执行的方法
|
||||
*/
|
||||
public static void match(String pattern, String excludePattern, SaFunction function) {
|
||||
if(isMatchCurrURI(pattern)) {
|
||||
if(isMatchCurrURI(excludePattern) == false) {
|
||||
function.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配,如果匹配成功则执行认证函数
|
||||
* @param patterns 路由匹配符集合
|
||||
* @param function 要执行的方法
|
||||
*/
|
||||
public static void match(List<String> patterns, SaFunction function) {
|
||||
if(isMatchCurrURI(patterns)) {
|
||||
function.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配 (并指定排除匹配符),如果匹配成功则执行认证函数
|
||||
* @param patterns 路由匹配符集合
|
||||
* @param excludePatterns 要排除的路由匹配符集合
|
||||
* @param function 要执行的方法
|
||||
*/
|
||||
public static void match(List<String> patterns, List<String> excludePatterns, SaFunction function) {
|
||||
if(isMatchCurrURI(patterns)) {
|
||||
if(isMatchCurrURI(excludePatterns) == false) {
|
||||
function.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 路由匹配,如果匹配成功则执行认证函数
|
||||
* @param patterns 路由匹配符集合
|
||||
* @return 匹配结果包装对象
|
||||
*/
|
||||
public static IsRunFunction match(String... patterns) {
|
||||
boolean matchResult = isMatch(Arrays.asList(patterns), SaHolder.getRequest().getRequestPath());
|
||||
return new IsRunFunction(matchResult);
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 其它操作 --------------------
|
||||
|
||||
/**
|
||||
* 停止匹配,跳出函数 (在多个匹配链中一次性跳出Auth函数)
|
||||
*/
|
||||
public static void stop() {
|
||||
throw new StopMatchException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止匹配,结束执行,向前端返回结果
|
||||
* @param result 要输出的结果
|
||||
*/
|
||||
public static void back(Object result) {
|
||||
throw new BackResultException(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止匹配,结束执行,向前端返回结果
|
||||
*/
|
||||
public static void back() {
|
||||
throw new BackResultException("");
|
||||
}
|
||||
|
||||
}
|
||||
+20
-40
@@ -1,49 +1,23 @@
|
||||
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.exception.StopMatchException;
|
||||
import cn.dev33.satoken.fun.IsRunFunction;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
|
||||
/**
|
||||
* <h1> 本类设计已过时,未来版本可能移除此类,请及时更换为 SaRouter ,使用方式保持不变 </h1>
|
||||
* 对路由匹配符相关操作的封装工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
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 +27,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 +51,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 +60,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,12 +123,21 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 其它操作 --------------------
|
||||
|
||||
/**
|
||||
* 停止匹配,跳出函数 (在多个匹配链中一次性跳出Auth函数)
|
||||
*/
|
||||
public static void stop() {
|
||||
throw new StopMatchException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* Base64工具类
|
||||
* Sa-Token Base64工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -57,5 +57,4 @@ public class SaBase64Util {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* sa-token 常见加密算法工具类
|
||||
* Sa-Token 常见加密算法工具类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
@@ -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,10 @@ import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.fun.SaRetFunction;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Session Model
|
||||
*
|
||||
@@ -34,6 +36,11 @@ public class SaSession implements Serializable {
|
||||
* 构建一个Session对象
|
||||
*/
|
||||
public SaSession() {
|
||||
/*
|
||||
* 当Session从Redis中反序列化取出时,框架会误以为创建了新的Session,
|
||||
* 因此此处不可以调用this(null); 避免监听器收到错误的通知
|
||||
*/
|
||||
// this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +50,8 @@ public class SaSession implements Serializable {
|
||||
public SaSession(String id) {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doCreateSession(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,81 +151,251 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- 存取值
|
||||
|
||||
// ----------------------- 一些操作
|
||||
|
||||
/**
|
||||
* 写入一个值
|
||||
*
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
* 更新Session(从持久库更新刷新一下)
|
||||
*/
|
||||
public void setAttribute(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
public void update() {
|
||||
SaManager.getSaTokenDao().updateSession(this);
|
||||
}
|
||||
|
||||
/** 注销Session (从持久库删除) */
|
||||
public void logout() {
|
||||
SaManager.getSaTokenDao().deleteSession(this.id);
|
||||
// $$ 通知监听器
|
||||
SaManager.getSaTokenListener().doLogoutSession(id);
|
||||
}
|
||||
|
||||
/** 当Session上的tokenSign数量为零时,注销会话 */
|
||||
public void logoutByTokenSignCountToZero() {
|
||||
if (tokenSignList.size() == 0) {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出一个值
|
||||
*
|
||||
* @param key 名称
|
||||
* @return 值
|
||||
* 获取此Session的剩余存活时间 (单位: 秒)
|
||||
* @return 此Session的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
public Object getAttribute(String key) {
|
||||
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 key 名称
|
||||
* @param defaultValue 取不到值的时候返回的默认值
|
||||
* @return value
|
||||
*
|
||||
* 取值 (指定默认值)
|
||||
* @param <T> 默认值的类型
|
||||
* @param key key
|
||||
* @param defaultValue 取不到值时返回的默认值
|
||||
* @return 值
|
||||
*/
|
||||
public Object getAttribute(String key, Object defaultValue) {
|
||||
Object value = getAttribute(key);
|
||||
if (value != null) {
|
||||
return value;
|
||||
public <T> T get(String key, T defaultValue) {
|
||||
return getValueByDefaultValue(get(key), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 取值 (如果值为null,则执行fun函数获取值)
|
||||
* @param <T> 返回值的类型
|
||||
* @param key key
|
||||
* @param fun 值为null时执行的函数
|
||||
* @return 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key, SaRetFunction fun) {
|
||||
Object value = get(key);
|
||||
if(value == null) {
|
||||
value = fun.run();
|
||||
set(key, value);
|
||||
}
|
||||
return defaultValue;
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转String类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = get(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个值
|
||||
*
|
||||
* @param key 要移除的值的名字
|
||||
* 取值 (转int类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public void removeAttribute(String key) {
|
||||
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 SaFoxUtil.getValueByType(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 SaFoxUtil.getValueByType(value, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前Session的所有key
|
||||
*
|
||||
* @return 所有值的key列表
|
||||
*/
|
||||
public Set<String> keys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
// ---- 其他
|
||||
/**
|
||||
* 写值
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有值
|
||||
*/
|
||||
public void clearAttribute() {
|
||||
public void clear() {
|
||||
dataMap.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有指定key
|
||||
*
|
||||
* @param key 是否含有指定值
|
||||
* @return 是否含有
|
||||
*/
|
||||
public boolean containsAttribute(String key) {
|
||||
return dataMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前session会话所有key
|
||||
*
|
||||
* @return 所有值的key列表
|
||||
*/
|
||||
public Set<String> attributeKeys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据挂载集合(如果更新map里的值,请调用session.update()方法避免产生脏数据 )
|
||||
*
|
||||
@@ -237,17 +416,8 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- 存取值 (类型转换)
|
||||
// --------- 工具方法
|
||||
|
||||
/**
|
||||
* 从Session中取值,转化为Object类型
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public Object getObject(String key) {
|
||||
return getAttribute(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个值是否为null
|
||||
* @param value 指定值
|
||||
@@ -257,26 +427,118 @@ public class SaSession implements Serializable {
|
||||
return value == null || value.equals("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据默认值来获取值
|
||||
* @param <T> 泛型
|
||||
* @param value 值
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换后的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getValueByDefaultValue(Object value, T defaultValue) {
|
||||
|
||||
// 如果 obj 为 null,则直接返回默认值
|
||||
if(valueIsNull(value)) {
|
||||
return (T)defaultValue;
|
||||
}
|
||||
|
||||
// 开始转换
|
||||
Class<T> cs = (Class<T>) defaultValue.getClass();
|
||||
return SaFoxUtil.getValueByType(value, cs);
|
||||
}
|
||||
|
||||
// ----------------------- 一些操作
|
||||
|
||||
|
||||
|
||||
// ----------------------- 旧API
|
||||
|
||||
/**
|
||||
* 将这个Session从持久库更新一下
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.set(key) </h1>
|
||||
* 写入一个值
|
||||
*
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getSaTokenDao().updateSession(this);
|
||||
@Deprecated
|
||||
public void setAttribute(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
|
||||
/** 注销会话 (注销后,此session会话将不再存储服务器上) */
|
||||
public void logout() {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(this.id);
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.get(key) </h1>
|
||||
* 取出一个值
|
||||
*
|
||||
* @param key 名称
|
||||
* @return 值
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getAttribute(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/** 当Session上的tokenSign数量为零时,注销会话 */
|
||||
public void logoutByTokenSignCountToZero() {
|
||||
if (tokenSignList.size() == 0) {
|
||||
logout();
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.get(key, defaultValue) </h1>
|
||||
* 取值,并指定取不到值时的默认值
|
||||
*
|
||||
* @param key 名称
|
||||
* @param defaultValue 取不到值的时候返回的默认值
|
||||
* @return value
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getAttribute(String key, Object defaultValue) {
|
||||
Object value = getAttribute(key);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.delete(key) </h1>
|
||||
* 移除一个值
|
||||
*
|
||||
* @param key 要移除的值的名字
|
||||
*/
|
||||
@Deprecated
|
||||
public void removeAttribute(String key) {
|
||||
dataMap.remove(key);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.clear() </h1>
|
||||
* 清空所有值
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearAttribute() {
|
||||
dataMap.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.has(key) </h1>
|
||||
* 是否含有指定key
|
||||
*
|
||||
* @param key 是否含有指定值
|
||||
* @return 是否含有
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean containsAttribute(String key) {
|
||||
return dataMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 此函数设计已过时,未来版本可能移除此类,请及时更换为: session.keys() </h1>
|
||||
* 返回当前session会话所有key
|
||||
*
|
||||
* @return 所有值的key列表
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<String> attributeKeys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* 自定义Session工具类
|
||||
@@ -11,28 +11,28 @@ import cn.dev33.satoken.SaTokenManager;
|
||||
public class SaSessionCustomUtil {
|
||||
|
||||
/**
|
||||
* 添加上指定前缀,防止恶意伪造session
|
||||
* 添加上指定前缀,防止恶意伪造Session
|
||||
*/
|
||||
public static String sessionKey = "custom";
|
||||
|
||||
/**
|
||||
* 组织一下自定义Session的id
|
||||
* 拼接Key: 自定义Session的Id
|
||||
*
|
||||
* @param sessionId 会话id
|
||||
* @return sessionId
|
||||
*/
|
||||
public static String splicingSessionKey(String sessionId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
|
||||
return SaManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证指定key的Session是否存在
|
||||
* 指定key的Session是否存在
|
||||
*
|
||||
* @param sessionId session的id
|
||||
* @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;
|
||||
}
|
||||
@@ -62,12 +62,12 @@ public class SaSessionCustomUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定key的session
|
||||
* 删除指定key的Session
|
||||
*
|
||||
* @param sessionId 指定key
|
||||
*/
|
||||
public static void deleteSessionById(String sessionId) {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
|
||||
SaManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package cn.dev33.satoken.session;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* token签名 Model
|
||||
* Token签名 Model
|
||||
*
|
||||
* 挂在到SaSession上的token签名
|
||||
*
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.dev33.satoken.sso;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO模块相关常量
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSsoConsts {
|
||||
|
||||
/** redirect参数名称 */
|
||||
public static final String REDIRECT_NAME = "redirect";
|
||||
|
||||
/** ticket参数名称 */
|
||||
public static final String TICKET_NAME = "ticket";
|
||||
|
||||
/** back参数名称 */
|
||||
public static final String BACK_NAME = "back";
|
||||
|
||||
/** loginId参数名称 */
|
||||
public static final String LOGIN_ID_NAME = "loginId";
|
||||
|
||||
/** secretkey参数名称 */
|
||||
public static final String SECRETKEY = "secretkey";
|
||||
|
||||
/** Client端单点注销时-回调URL 参数名称 */
|
||||
public static final String SLO_CALLBACK_NAME = "sloCallback";
|
||||
|
||||
/** Client端单点注销回调URL的Set集合,存储在Session中使用的key */
|
||||
public static final String SLO_CALLBACK_SET_KEY = "SLO_CALLBACK_SET_KEY_";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
package cn.dev33.satoken.sso;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaSsoConfig;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO 单点登录接口
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaSsoInterface {
|
||||
|
||||
/**
|
||||
* 创建一个 Ticket码
|
||||
* @param loginId 账号id
|
||||
* @return 票据
|
||||
*/
|
||||
public default String createTicket(Object loginId) {
|
||||
// 随机一个ticket
|
||||
String ticket = randomTicket(loginId);
|
||||
|
||||
// 保存入库
|
||||
long ticketTimeout = SaManager.getConfig().getSso().getTicketTimeout();
|
||||
SaManager.getSaTokenDao().set(splicingKeyTicketToId(ticket), String.valueOf(loginId), ticketTimeout);
|
||||
SaManager.getSaTokenDao().set(splicingKeyIdToTicket(loginId), String.valueOf(ticket), ticketTimeout);
|
||||
|
||||
// 返回
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个 Ticket码
|
||||
* @param ticket Ticket码
|
||||
*/
|
||||
public default void deleteTicket(String ticket) {
|
||||
Object loginId = getLoginId(ticket);
|
||||
if(loginId != null) {
|
||||
SaManager.getSaTokenDao().delete(splicingKeyTicketToId(ticket));
|
||||
SaManager.getSaTokenDao().delete(splicingKeyIdToTicket(loginId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端向Client下放ticke的地址
|
||||
* @param loginId 账号id
|
||||
* @param redirect Client端提供的重定向地址
|
||||
* @return see note
|
||||
*/
|
||||
public default String buildRedirectUrl(Object loginId, String redirect) {
|
||||
// 校验重定向地址
|
||||
checkRedirectUrl(redirect);
|
||||
|
||||
// 删掉旧ticket
|
||||
String oldTicket = SaManager.getSaTokenDao().get(splicingKeyIdToTicket(loginId));
|
||||
if(oldTicket != null) {
|
||||
deleteTicket(oldTicket);
|
||||
}
|
||||
|
||||
// 获取新ticket
|
||||
String ticket = createTicket(loginId);
|
||||
|
||||
// 构建 授权重定向地址
|
||||
redirect = encodeBackParam(redirect);
|
||||
String redirectUrl = SaFoxUtil.joinParam(redirect, SaSsoConsts.TICKET_NAME, ticket);
|
||||
return redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Ticket码 获取账号id,如果Ticket码无效则返回null
|
||||
* @param ticket Ticket码
|
||||
* @return 账号id
|
||||
*/
|
||||
public default Object getLoginId(String ticket) {
|
||||
if(SaFoxUtil.isEmpty(ticket)) {
|
||||
return null;
|
||||
}
|
||||
return SaManager.getSaTokenDao().get(splicingKeyTicketToId(ticket));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Ticket码 获取账号id,并转换为指定类型
|
||||
* @param <T> 要转换的类型
|
||||
* @param ticket Ticket码
|
||||
* @param cs 要转换的类型
|
||||
* @return 账号id
|
||||
*/
|
||||
public default <T> T getLoginId(String ticket, Class<T> cs) {
|
||||
return SaFoxUtil.getValueByType(getLoginId(ticket), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验ticket码,获取账号id,如果ticket可以有效,则立刻删除
|
||||
* @param ticket Ticket码
|
||||
* @return 账号id
|
||||
*/
|
||||
public default Object checkTicket(String ticket) {
|
||||
Object loginId = getLoginId(ticket);
|
||||
if(loginId != null) {
|
||||
deleteTicket(ticket);
|
||||
}
|
||||
return loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验重定向url合法性
|
||||
* @param url 下放ticket的url地址
|
||||
*/
|
||||
public default void checkRedirectUrl(String url) {
|
||||
|
||||
// 1、是否是一个有效的url
|
||||
if(SaFoxUtil.isUrl(url) == false) {
|
||||
throw new SaTokenException("无效回调地址:" + url);
|
||||
}
|
||||
|
||||
// 2、截取掉?后面的部分
|
||||
int qIndex = url.indexOf("?");
|
||||
if(qIndex != -1) {
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
// 3、是否在[允许地址列表]之中
|
||||
String authUrl = SaManager.getConfig().getSso().getAllowUrl().replaceAll(" ", "");
|
||||
List<String> authUrlList = Arrays.asList(authUrl.split(","));
|
||||
if(SaManager.getSaTokenAction().hasElement(authUrlList, url) == false) {
|
||||
throw new SaTokenException("非法回调地址:" + url);
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端 单点登录地址
|
||||
* @param clientLoginUrl Client端登录地址
|
||||
* @param back 回调路径
|
||||
* @return [SSO-Server端-认证地址 ]
|
||||
*/
|
||||
public default String buildServerAuthUrl(String clientLoginUrl, String back) {
|
||||
// 服务端认证地址
|
||||
String serverUrl = SaManager.getConfig().getSso().getAuthUrl();
|
||||
|
||||
// 对back地址编码
|
||||
back = (back == null ? "" : back);
|
||||
back = SaFoxUtil.encodeUrl(back);
|
||||
|
||||
// 拼接最终地址,格式示例:serverAuthUrl = http://xxx.com?redirectUrl=xxx.com?back=xxx.com
|
||||
clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, SaSsoConsts.BACK_NAME, back);
|
||||
String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, SaSsoConsts.REDIRECT_NAME, clientLoginUrl);
|
||||
|
||||
// 返回
|
||||
return serverAuthUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对url中的back参数进行URL编码, 解决超链接重定向后参数丢失的bug
|
||||
* @param url url
|
||||
* @return 编码过后的url
|
||||
*/
|
||||
public default String encodeBackParam(String url) {
|
||||
|
||||
// 获取back参数所在位置
|
||||
int index = url.indexOf("?" + SaSsoConsts.BACK_NAME + "=");
|
||||
if(index == -1) {
|
||||
index = url.indexOf("&" + SaSsoConsts.BACK_NAME + "=");
|
||||
if(index == -1) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
// 开始编码
|
||||
int length = SaSsoConsts.BACK_NAME.length() + 2;
|
||||
String back = url.substring(index + length);
|
||||
back = SaFoxUtil.encodeUrl(back);
|
||||
|
||||
// 放回url中
|
||||
url = url.substring(0, index + length) + back;
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机一个 Ticket码
|
||||
* @param loginId 账号id
|
||||
* @return 票据
|
||||
*/
|
||||
public default String randomTicket(Object loginId) {
|
||||
return SaFoxUtil.getRandomString(64);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- SSO 模式三 -------------------
|
||||
|
||||
/**
|
||||
* 校验secretkey秘钥是否有效
|
||||
* @param secretkey 秘钥
|
||||
*/
|
||||
public default void checkSecretkey(String secretkey) {
|
||||
if(secretkey == null || secretkey.isEmpty() || secretkey.equals(SaManager.getConfig().getSso().getSecretkey()) == false) {
|
||||
throw new SaTokenException("无效秘钥:" + secretkey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:校验ticket的URL
|
||||
* @param ticket ticket码
|
||||
* @param sloCallbackUrl 单点注销时的回调URL
|
||||
* @return 构建完毕的URL
|
||||
*/
|
||||
public default String buildCheckTicketUrl(String ticket, String sloCallbackUrl) {
|
||||
String url = SaManager.getConfig().getSso().getCheckTicketUrl();
|
||||
// 拼接ticket参数
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.TICKET_NAME, ticket);
|
||||
// 拼接单点注销时的回调URL
|
||||
if(sloCallbackUrl != null) {
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.SLO_CALLBACK_NAME, sloCallbackUrl);
|
||||
}
|
||||
// 返回
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定账号id注册单点注销回调URL
|
||||
* @param loginId 账号id
|
||||
* @param sloCallbackUrl 单点注销时的回调URL
|
||||
*/
|
||||
public default void registerSloCallbackUrl(Object loginId, String sloCallbackUrl) {
|
||||
if(loginId == null || sloCallbackUrl == null || sloCallbackUrl.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Set<String> urlSet = StpUtil.getSessionByLoginId(loginId).get(SaSsoConsts.SLO_CALLBACK_SET_KEY, ()-> new HashSet<String>());
|
||||
urlSet.add(sloCallbackUrl);
|
||||
StpUtil.getSessionByLoginId(loginId).set(SaSsoConsts.SLO_CALLBACK_SET_KEY, urlSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环调用Client端单点注销回调
|
||||
* @param loginId 账号id
|
||||
* @param fun 调用方法
|
||||
*/
|
||||
public default void forEachSloUrl(Object loginId, CallSloUrlFunction fun) {
|
||||
String secretkey = SaManager.getConfig().getSso().getSecretkey();
|
||||
Set<String> urlSet = StpUtil.getSessionByLoginId(loginId).get(SaSsoConsts.SLO_CALLBACK_SET_KEY,
|
||||
() -> new HashSet<String>());
|
||||
|
||||
for (String url : urlSet) {
|
||||
// 拼接:login参数、秘钥参数
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.LOGIN_ID_NAME, loginId);
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.SECRETKEY, secretkey);
|
||||
// 调用
|
||||
fun.run(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:单点注销URL
|
||||
* @param loginId 要注销的账号id
|
||||
* @return 单点注销URL
|
||||
*/
|
||||
public default String buildSloUrl(Object loginId) {
|
||||
SaSsoConfig ssoConfig = SaManager.getConfig().getSso();
|
||||
String url = ssoConfig.getSloUrl();
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.LOGIN_ID_NAME, loginId);
|
||||
url = SaFoxUtil.joinParam(url, SaSsoConsts.SECRETKEY, ssoConfig.getSecretkey());
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号单点注销
|
||||
* @param secretkey 校验秘钥
|
||||
* @param loginId 指定账号
|
||||
* @param fun 调用方法
|
||||
*/
|
||||
public default void singleLogout(String secretkey, Object loginId, CallSloUrlFunction fun) {
|
||||
// step.1 校验秘钥
|
||||
checkSecretkey(secretkey);
|
||||
|
||||
// step.2 遍历通知Client端注销会话
|
||||
forEachSloUrl(loginId, fun);
|
||||
|
||||
// step.3 Server端注销
|
||||
// StpUtil.logoutByLoginId(loginId);
|
||||
StpUtil.logoutByTokenValue(StpUtil.getTokenValueByLoginId(loginId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------- 返回相应key -------------------
|
||||
|
||||
/**
|
||||
* 拼接key:Ticket 查 账号Id
|
||||
* @param ticket
|
||||
* @return key
|
||||
*/
|
||||
public default String splicingKeyTicketToId(String ticket) {
|
||||
return SaManager.getConfig().getTokenName() + ":ticket:" + ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接key:账号Id 反查 Ticket
|
||||
* @param id 账号id
|
||||
* @return key
|
||||
*/
|
||||
public default String splicingKeyIdToTicket(Object id) {
|
||||
return SaManager.getConfig().getTokenName() + ":id-ticket:" + id;
|
||||
}
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
static interface CallSloUrlFunction{
|
||||
/**
|
||||
* 调用function
|
||||
* @param url 注销回调URL
|
||||
*/
|
||||
public void run(String url);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package cn.dev33.satoken.sso;
|
||||
|
||||
import cn.dev33.satoken.sso.SaSsoInterface.CallSloUrlFunction;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO 单点登录工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSsoUtil {
|
||||
|
||||
/**
|
||||
* 底层 SaSsoServerInterface 对象
|
||||
*/
|
||||
public static SaSsoInterface saSsoInterface = new SaSsoInterface() {};
|
||||
|
||||
/**
|
||||
* 创建一个 Ticket票据
|
||||
* @param loginId 账号id
|
||||
* @return 票据
|
||||
*/
|
||||
public static String createTicket(Object loginId) {
|
||||
return saSsoInterface.createTicket(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个 Ticket码
|
||||
* @param ticket Ticket码
|
||||
*/
|
||||
public static void deleteTicket(String ticket) {
|
||||
saSsoInterface.deleteTicket(ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端向Client下放ticke的地址
|
||||
* @param loginId 账号id
|
||||
* @param redirect Client端提供的重定向地址
|
||||
* @return see note
|
||||
*/
|
||||
public static String buildRedirectUrl(Object loginId, String redirect) {
|
||||
return saSsoInterface.buildRedirectUrl(loginId, redirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Ticket码 获取账号id,如果Ticket码无效则返回null
|
||||
* @param ticket Ticket码
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object getLoginId(String ticket) {
|
||||
return saSsoInterface.getLoginId(ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Ticket码 获取账号id,并转换为指定类型
|
||||
* @param <T> 要转换的类型
|
||||
* @param ticket Ticket码
|
||||
* @param cs 要转换的类型
|
||||
* @return 账号id
|
||||
*/
|
||||
public static <T> T getLoginId(String ticket, Class<T> cs) {
|
||||
return saSsoInterface.getLoginId(ticket, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验ticket码,获取账号id,如果ticket可以有效,则立刻删除
|
||||
* @param ticket Ticket码
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object checkTicket(String ticket) {
|
||||
return saSsoInterface.checkTicket(ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验重定向url合法性
|
||||
* @param url 下放ticket的url地址
|
||||
*/
|
||||
public static void checkAuthUrl(String url) {
|
||||
saSsoInterface.checkRedirectUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:Server端 单点登录地址
|
||||
* @param clientLoginUrl Client端登录地址
|
||||
* @param back 回调路径
|
||||
* @return [SSO-Server端-认证地址 ]
|
||||
*/
|
||||
public static String buildServerAuthUrl(String clientLoginUrl, String back) {
|
||||
return saSsoInterface.buildServerAuthUrl(clientLoginUrl, back);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- SSO 模式三 -------------------
|
||||
|
||||
/**
|
||||
* 校验secretkey秘钥是否有效
|
||||
* @param secretkey 秘钥
|
||||
*/
|
||||
public static void checkSecretkey(String secretkey) {
|
||||
saSsoInterface.checkSecretkey(secretkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:校验ticket的URL
|
||||
* @param ticket ticket码
|
||||
* @param sloCallbackUrl 单点注销时的回调URL (如果不需要单点注销功能,此值可以填null)
|
||||
* @return 构建完毕的URL
|
||||
*/
|
||||
public static String buildCheckTicketUrl(String ticket, String sloCallbackUrl) {
|
||||
return saSsoInterface.buildCheckTicketUrl(ticket, sloCallbackUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定账号id注册单点注销回调URL
|
||||
* @param loginId 账号id
|
||||
* @param sloCallbackUrl 单点注销时的回调URL
|
||||
*/
|
||||
public static void registerSloCallbackUrl(Object loginId, String sloCallbackUrl) {
|
||||
saSsoInterface.registerSloCallbackUrl(loginId, sloCallbackUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环调用Client端单点注销回调
|
||||
* @param loginId 账号id
|
||||
* @param fun 调用方法
|
||||
*/
|
||||
public static void forEachSloUrl(Object loginId, CallSloUrlFunction fun) {
|
||||
saSsoInterface.forEachSloUrl(loginId, fun);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建URL:单点注销URL
|
||||
* @param loginId 要注销的账号id
|
||||
* @return 单点注销URL
|
||||
*/
|
||||
public static String buildSloUrl(Object loginId) {
|
||||
return saSsoInterface.buildSloUrl(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定账号单点注销
|
||||
* @param secretkey 校验秘钥
|
||||
* @param loginId 指定账号
|
||||
* @param fun 调用方法
|
||||
*/
|
||||
public static void singleLogout(String secretkey, Object loginId, CallSloUrlFunction fun) {
|
||||
saSsoInterface.singleLogout(secretkey, loginId, fun);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 调用 `StpUtil.setLogin()` 时的 [配置参数 Model ]
|
||||
* 调用 `StpUtil.login()` 时的 [配置参数 Model ]
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -30,14 +30,14 @@ public class SaLoginModel {
|
||||
|
||||
|
||||
/**
|
||||
* @return device
|
||||
* @return 参考 {@link #device}
|
||||
*/
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param device 要设置的 device
|
||||
* @param device 参考 {@link #device}
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setDevice(String device) {
|
||||
@@ -46,14 +46,14 @@ public class SaLoginModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return isLastingCookie
|
||||
* @return 参考 {@link #isLastingCookie}
|
||||
*/
|
||||
public Boolean getIsLastingCookie() {
|
||||
return isLastingCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isLastingCookie 要设置的 isLastingCookie
|
||||
* @param isLastingCookie 参考 {@link #isLastingCookie}
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setIsLastingCookie(Boolean isLastingCookie) {
|
||||
@@ -62,14 +62,14 @@ public class SaLoginModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return timeout
|
||||
* @return 参考 {@link #timeout}
|
||||
*/
|
||||
public Long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout 要设置的 timeout
|
||||
* @param timeout 参考 {@link #timeout}
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel setTimeout(long timeout) {
|
||||
@@ -79,7 +79,7 @@ public class SaLoginModel {
|
||||
|
||||
|
||||
/**
|
||||
* @return cookie时长
|
||||
* @return Cookie时长
|
||||
*/
|
||||
public int getCookieTimeout() {
|
||||
if(isLastingCookie == false) {
|
||||
@@ -91,13 +91,12 @@ public class SaLoginModel {
|
||||
return (int)(long)timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建对象,初始化默认值
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel build() {
|
||||
return build(SaTokenManager.getConfig());
|
||||
return build(SaManager.getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +117,6 @@ public class SaLoginModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 静态方法获取一个 SaLoginModel 对象
|
||||
* @return SaLoginModel 对象
|
||||
@@ -127,7 +125,6 @@ public class SaLoginModel {
|
||||
return new SaLoginModel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* toString
|
||||
*/
|
||||
@@ -136,7 +133,4 @@ public class SaLoginModel {
|
||||
return "SaLoginModel [device=" + device + ", isLastingCookie=" + isLastingCookie + ", timeout=" + timeout + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
/**
|
||||
* token信息Model: 用来描述一个token的常用参数
|
||||
* Token信息Model: 用来描述一个Token的常用参数
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
@@ -20,8 +20,8 @@ public class SaTokenInfo {
|
||||
/** 此token对应的LoginId,未登录时为null */
|
||||
public Object loginId;
|
||||
|
||||
/** LoginKey账号体系标识 */
|
||||
public String loginKey;
|
||||
/** 账号类型 */
|
||||
public String loginType;
|
||||
|
||||
/** token剩余有效期 (单位: 秒) */
|
||||
public long tokenTimeout;
|
||||
@@ -38,6 +38,11 @@ public class SaTokenInfo {
|
||||
/** 登录设备标识 */
|
||||
public String loginDevice;
|
||||
|
||||
/** 自定义数据 */
|
||||
public String tag;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return token名称
|
||||
*/
|
||||
@@ -95,17 +100,17 @@ public class SaTokenInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoginKey账号体系标识
|
||||
* @return 账号类型
|
||||
*/
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
public String getLoginType() {
|
||||
return loginType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loginKey LoginKey账号体系标识
|
||||
* @param loginType 账号类型
|
||||
*/
|
||||
public void setLoginKey(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
public void setLoginType(String loginType) {
|
||||
this.loginType = loginType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,15 +183,32 @@ public class SaTokenInfo {
|
||||
this.loginDevice = loginDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 自定义数据
|
||||
*/
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag 自定义数据
|
||||
*/
|
||||
public void setTag(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenInfo [tokenName=" + tokenName + ", tokenValue=" + tokenValue + ", isLogin=" + isLogin
|
||||
+ ", loginId=" + loginId + ", loginKey=" + loginKey + ", tokenTimeout=" + tokenTimeout
|
||||
+ ", loginId=" + loginId + ", loginType=" + loginType + ", tokenTimeout=" + tokenTimeout
|
||||
+ ", sessionTimeout=" + sessionTimeout + ", tokenSessionTimeout=" + tokenSessionTimeout
|
||||
+ ", tokenActivityTimeout=" + tokenActivityTimeout + ", loginDevice=" + loginDevice + "]";
|
||||
+ ", tokenActivityTimeout=" + tokenActivityTimeout + ", loginDevice=" + loginDevice + ", tag=" + tag
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,21 +10,21 @@ import java.util.List;
|
||||
public interface StpInterface {
|
||||
|
||||
/**
|
||||
* 返回指定 LoginId 所拥有的权限码集合
|
||||
* 返回指定账号id所拥有的权限码集合
|
||||
*
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 账号体系标识
|
||||
* @param loginType 账号类型
|
||||
* @return 该账号id具有的权限码集合
|
||||
*/
|
||||
public List<String> getPermissionList(Object loginId, String loginKey);
|
||||
public List<String> getPermissionList(Object loginId, String loginType);
|
||||
|
||||
/**
|
||||
* 返回指定loginId所拥有的角色标识集合
|
||||
* 返回指定账号id所拥有的角色标识集合
|
||||
*
|
||||
* @param loginId 账号id
|
||||
* @param loginKey 账号体系标识
|
||||
* @param loginType 账号类型
|
||||
* @return 该账号id具有的角色标识集合
|
||||
*/
|
||||
public List<String> getRoleList(Object loginId, String loginKey);
|
||||
public List<String> getRoleList(Object loginId, String loginType);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 对StpInterface接口默认的实现类
|
||||
* 对 {@link StpInterface} 接口默认的实现类
|
||||
* <p>
|
||||
* 如果开发者没有实现StpInterface接口,则使用此默认实现
|
||||
*
|
||||
@@ -13,12 +13,12 @@ import java.util.List;
|
||||
public class StpInterfaceDefaultImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginKey) {
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginKey) {
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,23 +6,27 @@ import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* 一个默认的实现
|
||||
* Sa-Token 权限验证工具类
|
||||
* @author kong
|
||||
*/
|
||||
public class StpUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 账号类型标识
|
||||
*/
|
||||
public static final String TYPE = "login";
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
public static StpLogic stpLogic = new StpLogic(TYPE);
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
* 获取当前 StpLogic 的账号类型
|
||||
* @return See Note
|
||||
*/
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginKey();
|
||||
public static String getLoginType(){
|
||||
return stpLogic.getLoginType();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +40,17 @@ public class StpUtil {
|
||||
return stpLogic.getTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话写入当前TokenValue
|
||||
* @param tokenValue token值
|
||||
* @param cookieTimeout Cookie存活时间(秒)
|
||||
*/
|
||||
public static void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
stpLogic.setTokenValue(tokenValue, cookieTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* 获取当前TokenValue
|
||||
* @return 当前tokenValue
|
||||
*/
|
||||
public static String getTokenValue() {
|
||||
@@ -45,7 +58,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的token信息
|
||||
* 获取当前会话的Token信息
|
||||
* @return token信息
|
||||
*/
|
||||
public static SaTokenInfo getTokenInfo() {
|
||||
@@ -56,49 +69,49 @@ public class StpUtil {
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* 会话登录
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
*/
|
||||
public static void setLoginId(Object loginId) {
|
||||
stpLogic.setLoginId(loginId);
|
||||
public static void login(Object id) {
|
||||
stpLogic.login(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id, 并指定登录设备
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* 会话登录,并指定登录设备
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
* @param device 设备标识
|
||||
*/
|
||||
public static void setLoginId(Object loginId, String device) {
|
||||
stpLogic.setLoginId(loginId, device);
|
||||
public static void login(Object id, String device) {
|
||||
stpLogic.login(id, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id, 并指定登录设备
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* 会话登录,并指定是否 [记住我]
|
||||
* @param id 账号id,建议的类型:(long | int | String)
|
||||
* @param isLastingCookie 是否为持久Cookie
|
||||
*/
|
||||
public static void setLoginId(Object loginId, boolean isLastingCookie) {
|
||||
stpLogic.setLoginId(loginId, isLastingCookie);
|
||||
public static void login(Object id, boolean isLastingCookie) {
|
||||
stpLogic.login(id, isLastingCookie);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在当前会话上登录id, 并指定所有登录参数Model
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* 会话登录,并指定所有登录参数Model
|
||||
* @param id 登录id,建议的类型:(long | int | String)
|
||||
* @param loginModel 此次登录的参数Model
|
||||
*/
|
||||
public static void setLoginId(Object loginId, SaLoginModel loginModel) {
|
||||
stpLogic.setLoginId(loginId, loginModel);
|
||||
public static void login(Object id, SaLoginModel loginModel) {
|
||||
stpLogic.login(id, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话注销登录
|
||||
* 会话注销
|
||||
*/
|
||||
public static void logout() {
|
||||
stpLogic.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定token的会话注销登录
|
||||
* 会话注销,根据指定Token
|
||||
* @param tokenValue 指定token
|
||||
*/
|
||||
public static void logoutByTokenValue(String tokenValue) {
|
||||
@@ -106,8 +119,8 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId的会话注销登录(踢人下线)
|
||||
* <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
|
||||
* 会话注销,根据账号id (踢人下线)
|
||||
* <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 </p>
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public static void logoutByLoginId(Object loginId) {
|
||||
@@ -115,7 +128,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定loginId指定设备的会话注销登录(踢人下线)
|
||||
* 会话注销,根据账号id and 设备标识 (踢人下线)
|
||||
* <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
@@ -123,19 +136,18 @@ public class StpUtil {
|
||||
public static void logoutByLoginId(Object loginId, String device) {
|
||||
stpLogic.logoutByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 查询相关
|
||||
|
||||
/**
|
||||
* 获取当前会话是否已经登录
|
||||
/**
|
||||
* 当前会话是否已经登录
|
||||
* @return 是否已登录
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
return stpLogic.isLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 检验当前会话是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public static void checkLogin() {
|
||||
@@ -151,7 +163,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回默认值
|
||||
* 获取当前会话账号id, 如果未登录,则返回默认值
|
||||
* @param <T> 返回类型
|
||||
* @param defaultValue 默认值
|
||||
* @return 登录id
|
||||
@@ -161,7 +173,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 如果未登录,则返回null
|
||||
* 获取当前会话账号id, 如果未登录,则返回null
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object getLoginIdDefaultNull() {
|
||||
@@ -169,7 +181,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为String
|
||||
* 获取当前会话账号id, 并转换为String类型
|
||||
* @return 账号id
|
||||
*/
|
||||
public static String getLoginIdAsString() {
|
||||
@@ -177,7 +189,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为int
|
||||
* 获取当前会话账号id, 并转换为int类型
|
||||
* @return 账号id
|
||||
*/
|
||||
public static int getLoginIdAsInt() {
|
||||
@@ -185,17 +197,17 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话登录id, 并转换为long
|
||||
* 获取当前会话账号id, 并转换为long类型
|
||||
* @return 账号id
|
||||
*/
|
||||
public static long getLoginIdAsLong() {
|
||||
return stpLogic.getLoginIdAsLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
/**
|
||||
* 获取指定Token对应的账号id,如果未登录,则返回 null
|
||||
* @param tokenValue token
|
||||
* @return 登录id
|
||||
* @return 账号id
|
||||
*/
|
||||
public static Object getLoginIdByToken(String tokenValue) {
|
||||
return stpLogic.getLoginIdByToken(tokenValue);
|
||||
@@ -204,46 +216,46 @@ public class StpUtil {
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
/**
|
||||
* 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回
|
||||
* @param loginId 账号id
|
||||
* @param isCreate 是否新建
|
||||
* @return SaSession
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
|
||||
return stpLogic.getSessionByLoginId(loginId, isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定key的session, 如果session尚未创建,则返回null
|
||||
* @param sessionId sessionId
|
||||
* @return session对象
|
||||
* 获取指定key的Session, 如果Session尚未创建,则返回null
|
||||
* @param sessionId SessionId
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getSessionBySessionId(String sessionId) {
|
||||
return stpLogic.getSessionBySessionId(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的session,如果session尚未创建,则新建并返回
|
||||
* 获取指定账号id的Session,如果Session尚未创建,则新建并返回
|
||||
* @param loginId 账号id
|
||||
* @return session会话
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getSessionByLoginId(Object loginId) {
|
||||
return stpLogic.getSessionByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session, 如果session尚未创建,isCreate=是否新建并返回
|
||||
* 获取当前会话的Session, 如果Session尚未创建,isCreate=是否新建并返回
|
||||
* @param isCreate 是否新建
|
||||
* @return 当前会话的session
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getSession(boolean isCreate) {
|
||||
return stpLogic.getSession(isCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的session,如果session尚未创建,则新建并返回
|
||||
* @return 当前会话的session
|
||||
* 获取当前会话的Session,如果Session尚未创建,则新建并返回
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getSession() {
|
||||
return stpLogic.getSession();
|
||||
@@ -253,17 +265,17 @@ public class StpUtil {
|
||||
// =================== token专属session ===================
|
||||
|
||||
/**
|
||||
* 获取指定token的专属session,如果session尚未创建,则新建并返回
|
||||
* @param tokenValue token值
|
||||
* @return session会话
|
||||
* 获取指定Token-Session,如果Session尚未创建,则新建并返回
|
||||
* @param tokenValue Token值
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getTokenSessionByToken(String tokenValue) {
|
||||
return stpLogic.getTokenSessionByToken(tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token的专属-session,如果session尚未创建,则新建并返回
|
||||
* @return session会话
|
||||
* 获取当前Token-Session,如果Session尚未创建,则新建并返回
|
||||
* @return Session对象
|
||||
*/
|
||||
public static SaSession getTokenSession() {
|
||||
return stpLogic.getTokenSession();
|
||||
@@ -272,7 +284,7 @@ public class StpUtil {
|
||||
|
||||
// =================== [临时过期] 验证相关 ===================
|
||||
|
||||
/**
|
||||
/**
|
||||
* 检查当前token 是否已经[临时过期],如果已经过期则抛出异常
|
||||
*/
|
||||
public static void checkActivityTimeout() {
|
||||
@@ -328,7 +340,7 @@ public class StpUtil {
|
||||
// =================== 角色验证操作 ===================
|
||||
|
||||
/**
|
||||
* 指定账号id是否含有角色标识, 返回true或false
|
||||
* 指定账号id是否含有角色标识, 返回true或false
|
||||
* @param loginId 账号id
|
||||
* @param role 角色标识
|
||||
* @return 是否含有指定角色标识
|
||||
@@ -420,7 +432,7 @@ public class StpUtil {
|
||||
// =================== id 反查token 相关操作 ===================
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue
|
||||
* 获取指定账号id的tokenValue
|
||||
* <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
|
||||
* 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
|
||||
* @param loginId 账号id
|
||||
@@ -431,7 +443,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId指定设备端的tokenValue
|
||||
* 获取指定账号id指定设备端的tokenValue
|
||||
* <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
|
||||
* 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
|
||||
* @param loginId 账号id
|
||||
@@ -442,8 +454,8 @@ public class StpUtil {
|
||||
return stpLogic.getTokenValueByLoginId(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId的tokenValue集合
|
||||
/**
|
||||
* 获取指定账号id的tokenValue集合
|
||||
* @param loginId 账号id
|
||||
* @return 此loginId的所有相关token
|
||||
*/
|
||||
@@ -451,8 +463,8 @@ public class StpUtil {
|
||||
return stpLogic.getTokenValueListByLoginId(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定loginId指定设备端的tokenValue集合
|
||||
/**
|
||||
* 获取指定账号id指定设备端的tokenValue 集合
|
||||
* @param loginId 账号id
|
||||
* @param device 设备标识
|
||||
* @return 此loginId的所有相关token
|
||||
@@ -462,7 +474,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前token的登录设备
|
||||
* 返回当前会话的登录设备
|
||||
* @return 当前令牌的登录设备
|
||||
*/
|
||||
public static String getLoginDevice() {
|
||||
@@ -473,7 +485,7 @@ public class StpUtil {
|
||||
// =================== 会话管理 ===================
|
||||
|
||||
/**
|
||||
* 根据条件查询token
|
||||
* 根据条件查询Token
|
||||
* @param keyword 关键字
|
||||
* @param start 开始处索引 (-1代表查询所有)
|
||||
* @param size 获取数量
|
||||
@@ -495,7 +507,7 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询token专属Session的Id
|
||||
* 根据条件查询Token专属Session的Id
|
||||
* @param keyword 关键字
|
||||
* @param start 开始处索引 (-1代表查询所有)
|
||||
* @param size 获取数量
|
||||
@@ -504,12 +516,51 @@ public class StpUtil {
|
||||
public static List<String> searchTokenSessionId(String keyword, int start, int size) {
|
||||
return stpLogic.searchTokenSessionId(keyword, start, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------- 账号封禁 -------------------
|
||||
|
||||
/**
|
||||
* 封禁指定账号
|
||||
* <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);
|
||||
}
|
||||
|
||||
|
||||
// =================== 身份切换 ===================
|
||||
|
||||
/**
|
||||
* 临时切换身份为指定loginId
|
||||
* 临时切换身份为指定账号id
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public static void switchTo(Object loginId) {
|
||||
@@ -532,13 +583,109 @@ public class StpUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 在一个代码段里方法内,临时切换身份为指定loginId
|
||||
* @param loginId 指定loginId
|
||||
* 在一个代码段里方法内,临时切换身份为指定账号id
|
||||
* @param loginId 指定账号id
|
||||
* @param function 要执行的方法
|
||||
*/
|
||||
public static void switchTo(Object loginId, SaFunction function) {
|
||||
stpLogic.switchTo(loginId, function);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 二级认证 -------------------
|
||||
|
||||
/**
|
||||
* 在当前会话 开启二级认证
|
||||
* @param safeTime 维持时间 (单位: 秒)
|
||||
*/
|
||||
public static void openSafe(long safeTime) {
|
||||
stpLogic.openSafe(safeTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话 是否处于二级认证时间内
|
||||
* @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
|
||||
*/
|
||||
public static boolean isSafe() {
|
||||
return stpLogic.isSafe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前会话是否已通过二级认证,如未通过则抛出异常
|
||||
*/
|
||||
public static void checkSafe() {
|
||||
stpLogic.checkSafe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证)
|
||||
* @return 剩余有效时间
|
||||
*/
|
||||
public static long getSafeTime() {
|
||||
return stpLogic.getSafeTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话 结束二级认证
|
||||
*/
|
||||
public static void closeSafe() {
|
||||
stpLogic.closeSafe();
|
||||
}
|
||||
|
||||
|
||||
// =================== 历史API,兼容旧版本 ===================
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.getLoginType() ,使用方式保持不变 </h1>
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getLoginKey(){
|
||||
return stpLogic.getLoginType();
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
|
||||
* 在当前会话上登录id
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setLoginId(Object loginId) {
|
||||
stpLogic.login(loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
|
||||
* 在当前会话上登录id, 并指定登录设备
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* @param device 设备标识
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setLoginId(Object loginId, String device) {
|
||||
stpLogic.login(loginId, device);
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
|
||||
* 在当前会话上登录id, 并指定登录设备
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* @param isLastingCookie 是否为持久Cookie
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setLoginId(Object loginId, boolean isLastingCookie) {
|
||||
stpLogic.login(loginId, isLastingCookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
|
||||
* 在当前会话上登录id, 并指定所有登录参数Model
|
||||
* @param loginId 登录id,建议的类型:(long | int | String)
|
||||
* @param loginModel 此次登录的参数Model
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setLoginId(Object loginId, SaLoginModel loginModel) {
|
||||
stpLogic.login(loginId, loginModel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package cn.dev33.satoken.temp;
|
||||
|
||||
/**
|
||||
* Sa-Token 临时令牌验证模块 默认实现类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTempDefaultImpl implements SaTempInterface {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package cn.dev33.satoken.temp;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token 临时令牌验证模块接口
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public interface SaTempInterface {
|
||||
|
||||
/**
|
||||
* 根据value创建一个token
|
||||
* @param value 指定值
|
||||
* @param timeout 有效期,单位:秒
|
||||
* @return 生成的token
|
||||
*/
|
||||
public default String createToken(Object value, long timeout) {
|
||||
|
||||
// 生成 token
|
||||
String token = SaManager.getSaTokenAction().createToken(null, null);
|
||||
|
||||
// 持久化映射关系
|
||||
String key = splicingKeyTempToken(token);
|
||||
SaManager.getSaTokenDao().setObject(key, value, timeout);
|
||||
|
||||
// 返回
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token获取value
|
||||
* @param token 指定token
|
||||
* @return See Note
|
||||
*/
|
||||
public default Object parseToken(String token) {
|
||||
String key = splicingKeyTempToken(token);
|
||||
return SaManager.getSaTokenDao().getObject(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token获取value,并转换为指定类型
|
||||
* @param token 指定token
|
||||
* @param cs 指定类型
|
||||
* @param <T> 默认值的类型
|
||||
* @return See Note
|
||||
*/
|
||||
public default<T> T parseToken(String token, Class<T> cs) {
|
||||
return SaFoxUtil.getValueByType(parseToken(token), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定 token 的剩余有效期,单位:秒
|
||||
* <p> 返回值 -1 代表永久,-2 代表token无效
|
||||
* @param token see note
|
||||
* @return see note
|
||||
*/
|
||||
public default long getTimeout(String token) {
|
||||
String key = splicingKeyTempToken(token);
|
||||
return SaManager.getSaTokenDao().getObjectTimeout(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取映射关系的持久化key
|
||||
* @param token token值
|
||||
* @return key
|
||||
*/
|
||||
public default String splicingKeyTempToken(String token) {
|
||||
return SaManager.getConfig().getTokenName() + ":temp-token:" + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效)
|
||||
*/
|
||||
public default String getJwtSecretKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.dev33.satoken.temp;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Sa-Token 临时验证令牌模块
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTempUtil {
|
||||
|
||||
/**
|
||||
* 根据value创建一个token
|
||||
* @param value 指定值
|
||||
* @param timeout 有效期,单位:秒
|
||||
* @return 生成的token
|
||||
*/
|
||||
public static String createToken(Object value, long timeout) {
|
||||
return SaManager.getSaTemp().createToken(value, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token获取value
|
||||
* @param token 指定token
|
||||
* @return See Note
|
||||
*/
|
||||
public static Object parseToken(String token) {
|
||||
return SaManager.getSaTemp().parseToken(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token获取value,并转换为指定类型
|
||||
* @param token 指定token
|
||||
* @param cs 指定类型
|
||||
* @param <T> 默认值的类型
|
||||
* @return See Note
|
||||
*/
|
||||
public static<T> T parseToken(String token, Class<T> cs) {
|
||||
return SaManager.getSaTemp().parseToken(token, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定 token 的剩余有效期,单位:秒
|
||||
* <p> 返回值 -1 代表永久,-2 代表token无效
|
||||
* @param token see note
|
||||
* @return see note
|
||||
*/
|
||||
public static long getTimeout(String token) {
|
||||
return SaManager.getSaTemp().getTimeout(token);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
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;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* Sa-Token 内部工具类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaFoxUtil {
|
||||
|
||||
/**
|
||||
* 打印 Sa-Token 版本字符画
|
||||
*/
|
||||
public static void printSaToken() {
|
||||
String str = "____ ____ ___ ____ _ _ ____ _ _ \r\n" + "[__ |__| __ | | | |_/ |___ |\\ | \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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字符串
|
||||
*
|
||||
* @param length 字符串的长度
|
||||
* @return 一个随机字符串
|
||||
*/
|
||||
public static String getRandomString(int length) {
|
||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = random.nextInt(62);
|
||||
sb.append(str.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定字符串是否为null或者空字符串
|
||||
* @param str 指定字符串
|
||||
* @return 是否为null或者空字符串
|
||||
*/
|
||||
public static boolean isEmpty(String str) {
|
||||
return str == null || "".equals(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以当前时间戳和随机int数字拼接一个随机字符串
|
||||
*
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String getMarking28() {
|
||||
return System.currentTimeMillis() + "" + new Random().nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将日期格式化 (yyyy-MM-dd HH:mm:ss)
|
||||
* @param date 日期
|
||||
* @return 格式化后的时间
|
||||
*/
|
||||
public static String formatDate(Date date){
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
* @param dataList 数据集合
|
||||
* @param prefix 前缀
|
||||
* @param keyword 关键字
|
||||
* @param start 起始位置 (-1代表查询所有)
|
||||
* @param size 获取条数
|
||||
* @return 符合条件的新数据集合
|
||||
*/
|
||||
public static List<String> searchList(Collection<String> dataList, String prefix, String keyword, int start,
|
||||
int size) {
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
if (keyword == null) {
|
||||
keyword = "";
|
||||
}
|
||||
// 挑选出所有符合条件的
|
||||
List<String> list = new ArrayList<String>();
|
||||
Iterator<String> keys = dataList.iterator();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
if (key.startsWith(prefix) && key.indexOf(keyword) > -1) {
|
||||
list.add(key);
|
||||
}
|
||||
}
|
||||
// 取指定段数据
|
||||
return searchList(list, start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
* @param list 数据集合
|
||||
* @param start 起始位置 (-1代表查询所有)
|
||||
* @param size 获取条数
|
||||
* @return 符合条件的新数据集合
|
||||
*/
|
||||
public static List<String> searchList(List<String> list, int start, int size) {
|
||||
// 取指定段数据
|
||||
if (start < 0) {
|
||||
return list;
|
||||
}
|
||||
int end = start + size;
|
||||
List<String> list2 = new ArrayList<String>();
|
||||
for (int i = start; i < end; i++) {
|
||||
if (i >= list.size()) {
|
||||
return list2;
|
||||
}
|
||||
list2.add(list.get(i));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定值转化为指定类型
|
||||
* @param <T> 泛型
|
||||
* @param obj 值
|
||||
* @param cs 类型
|
||||
* @return 转换后的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getValueByType(Object obj, Class<T> cs) {
|
||||
// 如果 obj 为 null 或者本来就是 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在url上拼接上kv参数并返回
|
||||
* @param url url
|
||||
* @param parameStr 参数, 例如 id=1001
|
||||
* @return 拼接后的url字符串
|
||||
*/
|
||||
public static String joinParam(String url, String parameStr) {
|
||||
// 如果参数为空, 直接返回
|
||||
if(parameStr == null || parameStr.length() == 0) {
|
||||
return url;
|
||||
}
|
||||
if(url == null) {
|
||||
url = "";
|
||||
}
|
||||
int index = url.indexOf('?');
|
||||
// ? 不存在
|
||||
if(index == -1) {
|
||||
return url + '?' + parameStr;
|
||||
}
|
||||
// ? 是最后一位
|
||||
if(index == url.length() - 1) {
|
||||
return url + parameStr;
|
||||
}
|
||||
// ? 是其中一位
|
||||
if(index > -1 && index < url.length() - 1) {
|
||||
String separatorChar = "&";
|
||||
// 如果最后一位是 不是&, 且 parameStr 第一位不是 &, 就增送一个 &
|
||||
if(url.lastIndexOf(separatorChar) != url.length() - 1 && parameStr.indexOf(separatorChar) != 0) {
|
||||
return url + separatorChar + parameStr;
|
||||
} else {
|
||||
return url + parameStr;
|
||||
}
|
||||
}
|
||||
// 正常情况下, 代码不可能执行到此
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在url上拼接上kv参数并返回
|
||||
* @param url url
|
||||
* @param key 参数名称
|
||||
* @param value 参数值
|
||||
* @return 拼接后的url字符串
|
||||
*/
|
||||
public static String joinParam(String url, String key, Object value) {
|
||||
// 如果参数为空, 直接返回
|
||||
if(isEmpty(url) || isEmpty(key) || isEmpty(String.valueOf(value))) {
|
||||
return url;
|
||||
}
|
||||
return joinParam(url, key + "=" + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组的所有元素使用逗号拼接在一起
|
||||
* @param arr 数组
|
||||
* @return 字符串,例: a,b,c
|
||||
*/
|
||||
public static String arrayJoin(String[] arr) {
|
||||
if(arr == null) {
|
||||
return "";
|
||||
}
|
||||
String str = "";
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
str += arr[i];
|
||||
if(i != arr.length - 1) {
|
||||
str += ",";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证URL的正则表达式
|
||||
*/
|
||||
public static final String URL_REGEX = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
|
||||
|
||||
/**
|
||||
* 使用正则表达式判断一个字符串是否为URL
|
||||
* @param str 字符串
|
||||
* @return 拼接后的url字符串
|
||||
*/
|
||||
public static boolean isUrl(String str) {
|
||||
if(str == null) {
|
||||
return false;
|
||||
}
|
||||
return str.toLowerCase().matches(URL_REGEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL编码
|
||||
* @param url see note
|
||||
* @return see note
|
||||
*/
|
||||
public static String encodeUrl(String url) {
|
||||
try {
|
||||
return URLEncoder.encode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new SaTokenException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* URL解码
|
||||
* @param url see note
|
||||
* @return see note
|
||||
*/
|
||||
public static String decoderUrl(String url) {
|
||||
try {
|
||||
return URLDecoder.decode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new SaTokenException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
/**
|
||||
* sa-token常量类
|
||||
* Sa-Token常量类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@@ -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.21.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
* 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,39 +46,56 @@ public class SaTokenConsts {
|
||||
* 常量key标记: 在进行临时身份切换时使用的key
|
||||
*/
|
||||
public static final String SWITCH_TO_SAVE_KEY = "SWITCH_TO_SAVE_KEY_";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 常量key标记: 在进行Token二级验证时使用的key
|
||||
*/
|
||||
public static final String SAFE_AUTH_SAVE_KEY = "SAFE_AUTH_SAVE_KEY_";
|
||||
|
||||
|
||||
// =================== token-style 相关 ===================
|
||||
|
||||
/**
|
||||
* token风格: uuid
|
||||
* Token风格: uuid
|
||||
*/
|
||||
public static final String TOKEN_STYLE_UUID = "uuid";
|
||||
|
||||
/**
|
||||
* token风格: 简单uuid (不带下划线)
|
||||
* Token风格: 简单uuid (不带下划线)
|
||||
*/
|
||||
public static final String TOKEN_STYLE_SIMPLE_UUID = "simple-uuid";
|
||||
|
||||
/**
|
||||
* token风格: 32位随机字符串
|
||||
* Token风格: 32位随机字符串
|
||||
*/
|
||||
public static final String TOKEN_STYLE_RANDOM_32 = "random-32";
|
||||
|
||||
/**
|
||||
* token风格: 64位随机字符串
|
||||
* Token风格: 64位随机字符串
|
||||
*/
|
||||
public static final String TOKEN_STYLE_RANDOM_64 = "random-64";
|
||||
|
||||
/**
|
||||
* token风格: 128位随机字符串
|
||||
* Token风格: 128位随机字符串
|
||||
*/
|
||||
public static final String TOKEN_STYLE_RANDOM_128 = "random-128";
|
||||
|
||||
/**
|
||||
* token风格: tik风格 (2_14_16)
|
||||
* 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,117 +0,0 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* sa-token 内部代码工具类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenInsideUtil {
|
||||
|
||||
/**
|
||||
* 打印 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";
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字符串
|
||||
*
|
||||
* @param length 字符串的长度
|
||||
* @return 一个随机字符串
|
||||
*/
|
||||
public static String getRandomString(int length) {
|
||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = random.nextInt(62);
|
||||
sb.append(str.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定字符串是否为null或者空字符串
|
||||
* @param str 指定字符串
|
||||
* @return 是否为null或者空字符串
|
||||
*/
|
||||
public static boolean isEmpty(String str) {
|
||||
return str == null || "".equals(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以当前时间戳和随机int数字拼接一个随机字符串
|
||||
*
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String getMarking28() {
|
||||
return System.currentTimeMillis() + "" + new Random().nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
* @param dataList 数据集合
|
||||
* @param prefix 前缀
|
||||
* @param keyword 关键字
|
||||
* @param start 起始位置 (-1代表查询所有)
|
||||
* @param size 获取条数
|
||||
* @return 符合条件的新数据集合
|
||||
*/
|
||||
public static List<String> searchList(Collection<String> dataList, String prefix, String keyword, int start,
|
||||
int size) {
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
if (keyword == null) {
|
||||
keyword = "";
|
||||
}
|
||||
// 挑选出所有符合条件的
|
||||
List<String> list = new ArrayList<String>();
|
||||
Iterator<String> keys = dataList.iterator();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
if (key.startsWith(prefix) && key.indexOf(keyword) > -1) {
|
||||
list.add(key);
|
||||
}
|
||||
}
|
||||
// 取指定段数据
|
||||
return searchList(list, start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
* @param list 数据集合
|
||||
* @param start 起始位置 (-1代表查询所有)
|
||||
* @param size 获取条数
|
||||
* @return 符合条件的新数据集合
|
||||
*/
|
||||
public static List<String> searchList(List<String> list, int start, int size) {
|
||||
// 取指定段数据
|
||||
if (start < 0) {
|
||||
return list;
|
||||
}
|
||||
int end = start + size;
|
||||
List<String> list2 = new ArrayList<String>();
|
||||
for (int i = start; i < end; i++) {
|
||||
if (i >= list.size()) {
|
||||
return list2;
|
||||
}
|
||||
list2.add(list.get(i));
|
||||
}
|
||||
return list2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SaTokenDemoApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +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代码方式进行配置
|
||||
*/
|
||||
@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 "登录失败";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<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-alone-redis</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>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.21.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- springboot依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</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>
|
||||
|
||||
<!-- sa-token整合redis (使用jackson序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>${sa-token-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 提供redis连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token插件:权限缓存与业务缓存分离 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-alone-redis</artifactId>
|
||||
<version>${sa-token-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- @ConfigurationProperties -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Sa-Token整合SpringBoot 示例
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SaTokenAloneRedisApplication {
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException {
|
||||
SpringApplication.run(SaTokenAloneRedisApplication.class, args);
|
||||
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.pj.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* ajax请求返回Json格式数据的封装
|
||||
*/
|
||||
public class AjaxJson implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 1L; // 序列化版本号
|
||||
|
||||
public static final int CODE_SUCCESS = 200; // 成功状态码
|
||||
public static final int CODE_ERROR = 500; // 错误状态码
|
||||
public static final int CODE_WARNING = 501; // 警告状态码
|
||||
public static final int CODE_NOT_JUR = 403; // 无权限状态码
|
||||
public static final int CODE_NOT_LOGIN = 401; // 未登录状态码
|
||||
public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码
|
||||
|
||||
public int code; // 状态码
|
||||
public String msg; // 描述信息
|
||||
public Object data; // 携带对象
|
||||
public Long dataCount; // 数据总数,用于分页
|
||||
|
||||
/**
|
||||
* 返回code
|
||||
* @return
|
||||
*/
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给msg赋值,连缀风格
|
||||
*/
|
||||
public AjaxJson setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
public String getMsg() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给data赋值,连缀风格
|
||||
*/
|
||||
public AjaxJson setData(Object data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将data还原为指定类型并返回
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getData(Class<T> cs) {
|
||||
return (T) data;
|
||||
}
|
||||
|
||||
// ============================ 构建 ==================================
|
||||
|
||||
public AjaxJson(int code, String msg, Object data, Long dataCount) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
this.dataCount = dataCount;
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
public static AjaxJson getSuccess() {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", null, null);
|
||||
}
|
||||
public static AjaxJson getSuccess(String msg) {
|
||||
return new AjaxJson(CODE_SUCCESS, msg, null, null);
|
||||
}
|
||||
public static AjaxJson getSuccess(String msg, Object data) {
|
||||
return new AjaxJson(CODE_SUCCESS, msg, data, null);
|
||||
}
|
||||
public static AjaxJson getSuccessData(Object data) {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
|
||||
}
|
||||
public static AjaxJson getSuccessArray(Object... data) {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
|
||||
}
|
||||
|
||||
// 返回失败
|
||||
public static AjaxJson getError() {
|
||||
return new AjaxJson(CODE_ERROR, "error", null, null);
|
||||
}
|
||||
public static AjaxJson getError(String msg) {
|
||||
return new AjaxJson(CODE_ERROR, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回警告
|
||||
public static AjaxJson getWarning() {
|
||||
return new AjaxJson(CODE_ERROR, "warning", null, null);
|
||||
}
|
||||
public static AjaxJson getWarning(String msg) {
|
||||
return new AjaxJson(CODE_WARNING, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回未登录
|
||||
public static AjaxJson getNotLogin() {
|
||||
return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null);
|
||||
}
|
||||
|
||||
// 返回没有权限的
|
||||
public static AjaxJson getNotJur(String msg) {
|
||||
return new AjaxJson(CODE_NOT_JUR, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回一个自定义状态码的
|
||||
public static AjaxJson get(int code, String msg){
|
||||
return new AjaxJson(code, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回分页和数据的
|
||||
public static AjaxJson getPageData(Long dataCount, Object data){
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount);
|
||||
}
|
||||
|
||||
// 返回,根据受影响行数的(大于0=ok,小于0=error)
|
||||
public static AjaxJson getByLine(int line){
|
||||
if(line > 0){
|
||||
return getSuccess("ok", line);
|
||||
}
|
||||
return getError("error").setData(line);
|
||||
}
|
||||
|
||||
// 返回,根据布尔值来确定最终结果的 (true=ok,false=error)
|
||||
public static AjaxJson getByBoolean(boolean b){
|
||||
return b ? getSuccess("ok") : getError("error");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public String toString() {
|
||||
String data_string = null;
|
||||
if(data == null){
|
||||
|
||||
} else if(data instanceof List){
|
||||
data_string = "List(length=" + ((List)data).size() + ")";
|
||||
} else {
|
||||
data_string = data.toString();
|
||||
}
|
||||
return "{"
|
||||
+ "\"code\": " + this.getCode()
|
||||
+ ", \"msg\": \"" + this.getMsg() + "\""
|
||||
+ ", \"data\": " + data_string
|
||||
+ ", \"dataCount\": " + dataCount
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.pj.test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* 测试专用Controller
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/test/")
|
||||
public class TestController {
|
||||
|
||||
@Autowired
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// 测试Sa-Token缓存, 浏览器访问: http://localhost:8081/test/login
|
||||
@RequestMapping("login")
|
||||
public AjaxJson login(@RequestParam(defaultValue="10001") String id) {
|
||||
System.out.println("--------------- 测试Sa-Token缓存");
|
||||
StpUtil.login(id);
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试业务缓存 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test() {
|
||||
System.out.println("--------------- 测试业务缓存");
|
||||
stringRedisTemplate.opsForValue().set("hello", "Hello World");
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
# Sa-Token配置
|
||||
sa-token:
|
||||
# Token名称 (同时也是cookie名称)
|
||||
token-name: satoken
|
||||
# Token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# Token风格
|
||||
token-style: uuid
|
||||
# 配置Sa-Token单独使用的Redis连接
|
||||
alone-redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 2
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 10ms
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数
|
||||
max-active: 200
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
spring:
|
||||
# 配置业务使用的Redis连接
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 0
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 10ms
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数
|
||||
max-active: 200
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.21.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -79,8 +79,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<!-- <version>2.3.1</version> -->
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
</project>
|
||||
+2
-2
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
+11
-11
@@ -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;
|
||||
@@ -90,10 +90,10 @@ public class SaTokenJwtUtil {
|
||||
}
|
||||
return String.valueOf(loginId);
|
||||
} catch (ExpiredJwtException e) {
|
||||
// throw NotLoginException.newInstance(StpUtil.stpLogic.loginKey, NotLoginException.TOKEN_TIMEOUT);
|
||||
// throw NotLoginException.newInstance(StpUtil.TYPE, NotLoginException.TOKEN_TIMEOUT);
|
||||
return NotLoginException.TOKEN_TIMEOUT;
|
||||
} catch (MalformedJwtException e) {
|
||||
throw NotLoginException.newInstance(StpUtil.stpLogic.loginKey, NotLoginException.INVALID_TOKEN);
|
||||
throw NotLoginException.newInstance(StpUtil.stpLogic.loginType, NotLoginException.INVALID_TOKEN);
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
}
|
||||
@@ -122,15 +122,15 @@ public class SaTokenJwtUtil {
|
||||
|
||||
// 重写 (在当前会话上登录id )
|
||||
@Override
|
||||
public void setLoginId(Object loginId, String device) {
|
||||
public void login(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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ public class SaTokenJwtUtil {
|
||||
info.tokenValue = getTokenValue();
|
||||
info.isLogin = isLogin();
|
||||
info.loginId = getLoginIdDefaultNull();
|
||||
info.loginKey = getLoginKey();
|
||||
info.loginType = getLoginType();
|
||||
info.tokenTimeout = getTokenTimeout();
|
||||
// info.sessionTimeout = getSessionTimeout();
|
||||
// info.tokenSessionTimeout = getTokenSessionTimeout();
|
||||
+8
-6
@@ -32,7 +32,7 @@ public class TestJwtController {
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginIdDefaultNull());
|
||||
|
||||
StpUtil.setLoginId(id); // 在当前会话登录此账号
|
||||
StpUtil.login(id); // 在当前会话登录此账号
|
||||
System.out.println("登录成功");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginId());
|
||||
@@ -60,9 +60,9 @@ public class TestJwtController {
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
StpUtil.getSession().setAttribute("name", new Date()); // 写入一个值
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().get("name"));
|
||||
StpUtil.getSession().set("name", new Date()); // 写入一个值
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().get("name"));
|
||||
System.out.println( new ObjectMapper().writeValueAsString(StpUtil.getSession()));
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
@@ -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.login(10001);
|
||||
System.out.println(StpUtil.getTokenInfo().getTokenValue());
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
spring:
|
||||
# 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
|
||||
|
||||
|
||||
+1
-1
@@ -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>
|
||||
+2
-2
@@ -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序列化方式) -->
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user