mirror of
https://gitee.com/dromara/sa-token.git
synced 2024-11-30 02:48:10 +08:00
优化文档
This commit is contained in:
parent
23a9fb3447
commit
cbc28d392b
@ -30,14 +30,14 @@ Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证
|
||||
|
||||
框架集成简单、开箱即用、API设计清爽,通过Sa-Token,你将以一种极其简单的方式实现系统的权限认证部分
|
||||
|
||||
- **登录验证** —— 单端登录、多端登录、同端互斥登录、七天内免登录
|
||||
- **权限验证** —— 权限认证、角色认证、会话二级认证
|
||||
- **登录认证** —— 单端登录、多端登录、同端互斥登录、七天内免登录
|
||||
- **权限认证** —— 权限认证、角色认证、会话二级认证
|
||||
- **Session会话** —— 全端共享Session、单端独享Session、自定义Session
|
||||
- **踢人下线** —— 根据账号id踢人下线、根据Token值踢人下线
|
||||
- **账号封禁** —— 指定天数封禁、永久封禁、设定解封时间
|
||||
- **持久层扩展** —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
|
||||
- **分布式会话** —— 提供jwt集成、共享数据中心两种分布式会话方案
|
||||
- **微服务网关鉴权** —— 适配Gateway、Soul、Zuul等常见网关的路由拦截认证
|
||||
- **微服务网关鉴权** —— 适配Gateway、ShenYu、Zuul等常见网关的路由拦截认证
|
||||
- **单点登录** —— 内置三种单点登录模式:无论是否跨域、是否共享Redis,都可以搞定
|
||||
- **二级认证** —— 在已登录的基础上再次认证,保证安全性
|
||||
- **独立Redis** —— 将权限缓存与业务缓存分离
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 集成
|
||||
# 集成 Sa-Token
|
||||
|
||||
------
|
||||
|
||||
@ -73,7 +73,7 @@ implementation 'cn.dev33:sa-token-core:${sa.top.version}'
|
||||
```
|
||||
<!-- tabs:end -->
|
||||
|
||||
注:JDK版本:`v1.8+`
|
||||
注:JDK版本:`v1.8+`,SpringBoot:`建议2.0以上`
|
||||
|
||||
|
||||
## 获取源码
|
||||
|
@ -9,7 +9,7 @@
|
||||
在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-springboot`(不会的同学请自行百度或者参考github示例)
|
||||
|
||||
|
||||
### 2、设置依赖
|
||||
### 2、添加依赖
|
||||
在 `pom.xml` 中添加依赖:
|
||||
|
||||
``` xml
|
||||
|
@ -1,17 +1,19 @@
|
||||
# Spring WebFlux 集成 Sa-Token 示例
|
||||
|
||||
WebFlux基于Reactor响应式模型开发,有着与标准ServletAPI完全不同的底层架构,因此要适配WebFlux, 必须提供与Reactor相关的整合实现,
|
||||
本篇将以WebFlux为例,展示Sa-Token与Reactor响应式模型web框架相整合的示例, **你可以用同样方式去对接其它Reactor模型Web框架**(Netty、ShenYu、Gateway等)
|
||||
**Reactor** 是一种非阻塞的响应式模型,本篇将 **WebFlux** 以为例,展示 Sa-Token 与 Reactor 响应式模型架相整合的示例,
|
||||
**你可以用同样方式去对接其它Reactor模型框架(Netty、ShenYu、SpringCloud Gateway等)**
|
||||
|
||||
整合示例在官方仓库的`/sa-token-demo/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习
|
||||
|
||||
!> WebFlux常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章
|
||||
|
||||
---
|
||||
|
||||
### 1、创建项目
|
||||
在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-webflux`(不会的同学请自行百度或者参考github示例)
|
||||
|
||||
|
||||
### 2、设置依赖
|
||||
### 2、添加依赖
|
||||
在 `pom.xml` 中添加依赖:
|
||||
|
||||
``` xml
|
||||
@ -24,7 +26,7 @@ WebFlux基于Reactor响应式模型开发,有着与标准ServletAPI完全不
|
||||
```
|
||||
|
||||
|
||||
### 4、创建启动类
|
||||
### 3、创建启动类
|
||||
在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,输入以下代码:
|
||||
|
||||
``` java
|
||||
@ -37,7 +39,7 @@ public class SaTokenDemoApplication {
|
||||
}
|
||||
```
|
||||
|
||||
### 5、创建全局过滤器
|
||||
### 4、创建全局过滤器
|
||||
新建`SaTokenConfigure.java`,注册Sa-Token的全局过滤器
|
||||
``` java
|
||||
/**
|
||||
@ -72,7 +74,7 @@ public class SaTokenConfigure {
|
||||
?> 你只需要按照此格式复制代码即可,有关过滤器的详细用法,会在之后的章节详细介绍
|
||||
|
||||
|
||||
### 6、创建测试Controller
|
||||
### 5、创建测试Controller
|
||||
``` java
|
||||
@RestController
|
||||
@RequestMapping("/user/")
|
||||
@ -98,7 +100,7 @@ public class UserController {
|
||||
}
|
||||
```
|
||||
|
||||
### 7、运行
|
||||
### 6、运行
|
||||
启动代码,从浏览器依次访问上述测试接口:
|
||||
|
||||
![运行结果](https://oss.dev33.cn/sa-token/doc/test-do-login.png)
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
### 获取当前账号权限码集合
|
||||
因为每个项目的需求不同,其权限设计也千变万化,因此【获取当前账号权限码集合】这一操作不可能内置到框架中,
|
||||
所以`Sa-Token`将此操作以接口的方式暴露给你,以方便的你根据自己的业务逻辑进行重写
|
||||
所以 Sa-Token 将此操作以接口的方式暴露给你,以方便的你根据自己的业务逻辑进行重写
|
||||
|
||||
你需要做的就是新建一个类,实现`StpInterface`接口,例如以下代码:
|
||||
|
||||
@ -156,5 +156,62 @@ StpUtil.hasPermission("index.html"); // false
|
||||
|
||||
注意:以上写法只为提供一个参考示例,不同框架有不同写法,开发者可根据项目技术栈灵活封装进行调用
|
||||
|
||||
|
||||
### 前端有了鉴权后端还需要鉴权吗?
|
||||
**需要!前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!**
|
||||
**需要!**
|
||||
|
||||
前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!
|
||||
|
||||
|
||||
### 将权限数据放在缓存里
|
||||
前面我们讲解了通过`StpInterface`接口将权限数据注入到框架中,框架默认是不提供缓存能力的,
|
||||
如果每次权限校验都要查库操作,势必会对数据库造成不小的压力,为了解决这个问题,我们需要将权限数据放到缓存中
|
||||
|
||||
参考示例:
|
||||
``` java
|
||||
/**
|
||||
* 返回一个账号所拥有的权限码集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
|
||||
// 1. 获取这个账号所属角色id
|
||||
long roleId = StpUtil.getSessionByLoginId(loginId).get("Role_Id", () -> {
|
||||
return ...; // 从数据库查询这个账号所属的角色id
|
||||
});
|
||||
|
||||
// 2. 获取这个角色id拥有的权限列表
|
||||
SaSession roleSession = SaSessionCustomUtil.getSessionById("role-" + roleId);
|
||||
List<String> list = roleSession.get("Permission_List", () -> {
|
||||
return ...; // 从数据库查询这个角色id拥有的权限列表
|
||||
});
|
||||
|
||||
// 3. 返回
|
||||
return list;
|
||||
}
|
||||
```
|
||||
以上仅为代码示例,角色列表步骤同理
|
||||
|
||||
##### 疑问:为什么不直接缓存 `[账号id->权限列表]`的关系,而是 `[账号id -> 角色id -> 权限列表]`?
|
||||
|
||||
<!-- ``` java
|
||||
// 在一个账号登录时写入其权限数据
|
||||
RedisUtil.setValue("账号id", <权限列表>);
|
||||
|
||||
// 然后在`StpInterface`接口中,如下方式获取
|
||||
List<String> list = RedisUtil.getValue("账号id");
|
||||
``` -->
|
||||
|
||||
答:`[账号id->权限列表]`的缓存方式虽然更加直接粗暴,却有一个严重的问题:
|
||||
|
||||
- 通常我们系统的权限架构是RBAC模型:权限与用户没有直接的关系,而是:用户拥有指定的角色,角色再拥有指定的权限
|
||||
- 而这种'拥有关系'是动态的,是可以随时修改的,一旦我们修改了它们的对应关系,便要同步修改或清除对应的缓存数据
|
||||
|
||||
现在假设如下业务场景:我们系统中有十万个账号属于同一个角色,当我们变动这个角色的权限时,难道我们要同时清除这十万个账号的缓存信息吗?
|
||||
这显然是一个不合理的操作,同一时间缓存大量清除容易引起Redis的缓存雪崩
|
||||
|
||||
而当我们采用 `[账号id -> 角色id -> 权限列表]` 的缓存模型时,则只需要清除或修改 `[角色id -> 权限列表]` 一条缓存即可
|
||||
|
||||
一言以蔽之:权限的缓存模型需要跟着权限模型走,角色缓存亦然
|
||||
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
### 核心思想
|
||||
|
||||
所谓登录认证,说白了就是限制某些接口只有登录后才能访问(如:查询我的账号资料) <br>
|
||||
那么判断一个会话是否登录的依据是什么?当然是登录成功后框架给你做个标记!然后在需要鉴权的接口里检查此标记,有标记者视为已登录,无标记者视为未登录!
|
||||
所谓登录认证,说白了就是限制某些API接口必须登录后才能访问(例:查询我的账号资料) <br>
|
||||
那么如何判断一个会话是否登录?框架会在登录成功后给你做个标记,每次登录认证时校验这个标记,有标记者视为已登录,无标记者视为未登录!
|
||||
|
||||
|
||||
### 登录与注销
|
||||
@ -26,33 +26,34 @@ StpUtil.isLogin();
|
||||
StpUtil.checkLogin()
|
||||
```
|
||||
|
||||
扩展:`NotLoginException` 对象可通过 `getLoginType()` 方法获取具体是哪个 `StpLogic` 抛出的异常 <br>
|
||||
扩展:`NotLoginException` 对象可通过 `getType()` 方法获取具体的场景值,详细参考章节:[未登录场景值](/fun/not-login-scene)
|
||||
##### `NotLoginException`异常对象扩展:
|
||||
1. 通过 `getLoginType()` 方法获取具体是哪个 `StpLogic` 抛出的异常 <br>
|
||||
2. 通过 `getType()` 方法获取具体的场景值,详细参考章节:[未登录场景值](/fun/not-login-scene)
|
||||
|
||||
|
||||
### 会话查询
|
||||
``` java
|
||||
// 获取当前会话登录id, 如果未登录,则抛出异常:`NotLoginException`
|
||||
// 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
|
||||
StpUtil.getLoginId();
|
||||
|
||||
// 类似查询API还有:
|
||||
StpUtil.getLoginIdAsString(); // 获取当前会话登录id, 并转化为`String`类型
|
||||
StpUtil.getLoginIdAsInt(); // 获取当前会话登录id, 并转化为`int`类型
|
||||
StpUtil.getLoginIdAsLong(); // 获取当前会话登录id, 并转化为`long`类型
|
||||
StpUtil.getLoginIdAsString(); // 获取当前会话账号id, 并转化为`String`类型
|
||||
StpUtil.getLoginIdAsInt(); // 获取当前会话账号id, 并转化为`int`类型
|
||||
StpUtil.getLoginIdAsLong(); // 获取当前会话账号id, 并转化为`long`类型
|
||||
|
||||
// ---------- 指定未登录情形下返回的默认值 ----------
|
||||
|
||||
// 获取当前会话登录id, 如果未登录,则返回null
|
||||
// 获取当前会话账号id, 如果未登录,则返回null
|
||||
StpUtil.getLoginIdDefaultNull();
|
||||
|
||||
// 获取当前会话登录id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
|
||||
// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
|
||||
StpUtil.getLoginId(T defaultValue);
|
||||
```
|
||||
|
||||
|
||||
### 其它API
|
||||
``` java
|
||||
// 获取指定token对应的登录id,如果未登录,则返回 null
|
||||
// 获取指定token对应的账号id,如果未登录,则返回 null
|
||||
StpUtil.getLoginIdByToken(String tokenValue);
|
||||
|
||||
// 获取当前`StpLogic`的token名称
|
||||
@ -65,6 +66,6 @@ StpUtil.getTokenValue();
|
||||
StpUtil.getTokenInfo();
|
||||
```
|
||||
|
||||
?> 有关TokenInfo参数详解,请参考:[参考:TokenInfo参数详解](/fun/token-info)
|
||||
有关`TokenInfo`参数详解,请参考:[TokenInfo参数详解](/fun/token-info)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user