增加代码示例

This commit is contained in:
click33
2022-10-17 00:25:28 +08:00
parent 7142f4db36
commit 55c981ac2d
22 changed files with 470 additions and 75 deletions

View File

@@ -39,13 +39,6 @@
<version>${sa-token-version}</version> <version>${sa-token-version}</version>
</dependency> </dependency>
<!-- Sa-Token 整合 Redis (使用jdk默认序列化方式) -->
<!-- <dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis</artifactId>
<version>${sa-token-version}</version>
</dependency> -->
<!-- Sa-Token整合 Redis (使用jackson序列化方式) --> <!-- Sa-Token整合 Redis (使用jackson序列化方式) -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>

View File

@@ -0,0 +1,63 @@
package com.pj.cases.up;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token 二级认证示例
*
* @author kong
* @since 2022-10-16
*/
@RestController
@RequestMapping("/safe/")
public class SafeAuthController {
/*
* 前提:首先调用登录接口进行登录,代码在 com.pj.cases.use.LoginAuthController 中有详细解释,此处不再赘述
*
* 测试步骤:
1、前端调用 deleteProject 接口,尝试删除仓库。 ---- http://localhost:8081/safe/deleteProject
2、后端校验会话尚未完成二级认证返回 仓库删除失败,请完成二级认证后再次访问接口。
3、前端将信息提示给用户用户输入密码调用 openSafe 接口。 ---- http://localhost:8081/safe/openSafe
4、后端比对用户输入的密码完成二级认证有效期为120秒。
5、前端在 120 秒内再次调用 deleteProject 接口,尝试删除仓库。 ---- http://localhost:8081/safe/deleteProject
6、后端校验会话已完成二级认证返回仓库删除成功。
*/
// 删除仓库 ---- http://localhost:8081/safe/deleteProject
@RequestMapping("deleteProject")
public SaResult deleteProject(String projectId) {
// 第1步先检查当前会话是否已完成二级认证
// 这个地方既可以通过 StpUtil.isSafe() 手动判断,
// 也可以通过 StpUtil.checkSafe() 或者 @SaCheckSafe 来校验(校验不通过时将抛出 NotSafeException 异常)
if(!StpUtil.isSafe()) {
return SaResult.error("仓库删除失败,请完成二级认证后再次访问接口");
}
// 第2步如果已完成二级认证则开始执行业务逻辑
// ...
// 第3步返回结果
return SaResult.ok("仓库删除成功");
}
// 提供密码进行二级认证 ---- http://localhost:8081/safe/openSafe
@RequestMapping("openSafe")
public SaResult openSafe(String password) {
// 比对密码(此处只是举例,真实项目时可拿其它参数进行校验)
if("123456".equals(password)) {
// 比对成功为当前会话打开二级认证有效期为120秒
StpUtil.openSafe(120);
return SaResult.ok("二级认证成功");
}
// 如果密码校验失败,则二级认证也会失败
return SaResult.error("二级认证失败");
}
}

View File

@@ -1,4 +1,4 @@
package com.pj.cases; package com.pj.cases.use;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -21,7 +21,7 @@ import cn.dev33.satoken.util.SaResult;
public class AtCheckController { public class AtCheckController {
/* /*
* 前提1首先调用登录接口进行登录代码在 com.pj.cases.LoginAuthController 中有详细解释此处不再赘述 * 前提1首先调用登录接口进行登录代码在 com.pj.cases.use.LoginAuthController 中有详细解释此处不再赘述
* ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 * ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
* *
* 前提2项目在配置类中注册拦截器 SaInterceptor 代码在 com.pj.satoken.SaTokenConfigure * 前提2项目在配置类中注册拦截器 SaInterceptor 代码在 com.pj.satoken.SaTokenConfigure

View File

@@ -1,4 +1,4 @@
package com.pj.cases; package com.pj.cases.use;
import java.util.List; import java.util.List;
@@ -19,7 +19,7 @@ import cn.dev33.satoken.util.SaResult;
public class JurAuthController { public class JurAuthController {
/* /*
* 前提1首先调用登录接口进行登录代码在 com.pj.cases.LoginAuthController 中有详细解释此处不再赘述 * 前提1首先调用登录接口进行登录代码在 com.pj.cases.use.LoginAuthController 中有详细解释此处不再赘述
* ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 * ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
* *
* 前提2项目实现 StpInterface 接口代码在 com.pj.satoken.StpInterfaceImpl * 前提2项目实现 StpInterface 接口代码在 com.pj.satoken.StpInterfaceImpl

View File

@@ -1,4 +1,4 @@
package com.pj.cases; package com.pj.cases.use;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -17,7 +17,7 @@ import cn.dev33.satoken.util.SaResult;
public class KickoutController { public class KickoutController {
/* /*
* 前提首先调用登录接口进行登录代码在 com.pj.cases.LoginAuthController 中有详细解释此处不再赘述 * 前提首先调用登录接口进行登录代码在 com.pj.cases.use.LoginAuthController 中有详细解释此处不再赘述
* ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 * ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
*/ */

View File

@@ -1,4 +1,4 @@
package com.pj.cases; package com.pj.cases.use;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@@ -0,0 +1,27 @@
package com.pj.cases.use;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.util.SaResult;
/**
* 为路由拦截鉴权准备的路示例
*
* @author kong
* @since 2022-10-15
*/
@RestController
public class RouterCheckController {
// 路由拦截鉴权测试 ---- http://localhost:8081/xxx
@RequestMapping({
"/user/doLogin", "/user/doLogin2",
"/user/info", "/admin/info", "/goods/info", "/orders/info", "/notice/info", "/comment/info",
"/router/print", "/router/print2"
})
public SaResult checkLogin() {
return SaResult.ok();
}
}

View File

@@ -0,0 +1,99 @@
package com.pj.cases.use;
import java.util.Arrays;
import java.util.List;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.pj.model.SysUser;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaSessionCustomUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token Session会话示例
*
* @author kong
* @since 2022-10-15
*/
@RestController
@RequestMapping("/session/")
public class SaSessionController {
/*
* 前提:首先调用登录接口进行登录,代码在 com.pj.cases.use.LoginAuthController 中有详细解释,此处不再赘述
*/
// 简单存取值 ---- http://localhost:8081/session/getValue
@RequestMapping("getValue")
public SaResult getValue() {
// 获取当前登录账号的专属 SaSession 对象
// 注意点1只有登录后才可以调用这个方法
// 注意点2每个账号获取到的都是不同的 SaSession 对象,存取值时不会互相影响
// 注意点3SaSession 和 HttpSession 是两个完全不同的对象,不可混淆使用
SaSession session = StpUtil.getSession();
// 存值
session.set("name", "zhangsan");
session.set("age", 18);
// 取值
Object name = session.get("name");
String name2 = session.getString("name"); // 取值,并转化为 String 数据类型
int age = session.getInt("age"); // 转 int 类型
long age2 = session.getLong("age"); // 转 long 类型
float age3 = session.getFloat("age"); // 转 float 类型
double age4 = session.getDouble("age"); // 转 double 类型
int age5 = session.get("age5", 22); // 取不到时就返回默认值
int age6 = session.get("age5", () -> { // 取不到时就执行 lambda 获取值
return 26;
});
/*
* 存取值范围是一次会话有效的,也就是说,在一次登录有效期内,你可以在一个请求里存值,然后在另一个请求里取值
*/
List<Object> list = Arrays.asList(name, name2, age, age2, age3, age4, age5, age6);
System.out.println(list);
return SaResult.data(list);
}
// 复杂存取值 ---- http://localhost:8081/session/getModel
@RequestMapping("getModel")
public SaResult setValue() {
// 实例化
SysUser user = new SysUser();
user.setId(10001);
user.setName("张三");
user.setAge(19);
// 写入这个对象到 SaSession 中
StpUtil.getSession().set("user", user);
// 然后我们就可以在任意代码处获取这个 user 了
SysUser user2 = StpUtil.getSession().getModel("user", SysUser.class);
// 返回
return SaResult.data(user2);
}
// 自定义Session ---- http://localhost:8081/session/customSession
@RequestMapping("customSession")
public SaResult customSession() {
// 自定义 Session 就是指使用一个特定的 key来获取 Session 对象
SaSession roleSession = SaSessionCustomUtil.getSessionById("role-1001");
// 一样可以自由的存值写值
roleSession.set("nnn", "lalala");
System.out.println(roleSession.get("nnn"));
// 返回
return SaResult.ok();
}
}

View File

@@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException; import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.exception.NotSafeException;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
/** /**
@@ -39,6 +40,13 @@ public class GlobalException {
return SaResult.error("缺少角色:" + e.getRole()); return SaResult.error("缺少角色:" + e.getRole());
} }
// 拦截:二级认证校验失败异常
@ExceptionHandler(NotSafeException.class)
public SaResult handlerException(NotSafeException e) {
e.printStackTrace();
return SaResult.error("二级认证校验失败");
}
// 拦截:其它所有异常 // 拦截:其它所有异常
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public SaResult handlerException(Exception e) { public SaResult handlerException(Exception e) {

View File

@@ -0,0 +1,84 @@
package com.pj.model;
/**
* User 实体类
*
* @author kong
* @since 2022-10-15
*/
public class SysUser {
public SysUser() {
}
public SysUser(long id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
/**
* 用户id
*/
private long id;
/**
* 用户名称
*/
private String name;
/**
* 用户年龄
*/
private int age;
/**
* @return id
*/
public long getId() {
return id;
}
/**
* @param id 要设置的 id
*/
public void setId(long id) {
this.id = id;
}
/**
* @return name
*/
public String getName() {
return name;
}
/**
* @param name 要设置的 name
*/
public void setName(String name) {
this.name = name;
}
/**
* @return age
*/
public int getAge() {
return age;
}
/**
* @param age 要设置的 age
*/
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "SysUser [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}

View File

@@ -10,6 +10,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter; import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
@@ -28,7 +30,36 @@ public class SaTokenConfigure implements WebMvcConfigurer {
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器打开注解鉴权功能 // 注册 Sa-Token 拦截器打开注解鉴权功能
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); registry.addInterceptor(new SaInterceptor(handle -> {
// 指定一条 match 规则
SaRouter
.match("/user/**") // 拦截的 path 列表,可以写多个
.notMatch("/user/doLogin", "/user/doLogin2") // 排除掉的 path 列表,可以写多个
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式
// 权限校验 -- 不同模块认证不同权限
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
// 甚至你可以随意的写一个打印语句
SaRouter.match("/router/print", r -> System.out.println("----啦啦啦----"));
// 写一个完整的 lambda
SaRouter.match("/router/print2", r -> {
System.out.println("----啦啦啦2----");
// ... 其它代码
});
/*
* 相关路由都定义在 com.pj.cases.use.RouterCheckController 中
*/
})).addPathPatterns("/**");
} }
/** /**

View File

@@ -26,31 +26,57 @@
### 3、设置配置文件 ### 3、设置配置文件
你可以**零配置启动项目** ,但同时你也可以在 `application.yml` 中增加如下配置,定制性使用框架: 你可以**零配置启动项目** ,但同时你也可以在 `application.yml` 中增加如下配置,定制性使用框架:
<!------------------------------ tabs:start ------------------------------>
<!------------- tab:application.yml 风格 ------------->
``` java ``` java
server: server:
# 端口 # 端口
port: 8081 port: 8081
# Sa-Token配置 ############## Sa-Token 配置 ##############
sa-token: sa-token:
# token 名称 (同时也是cookie名称) # token名称 (同时也是cookie名称)
token-name: satoken token-name: satoken
# token 有效期单位s 默认30天, -1代表永不过期 # token有效期单位s 默认30天, -1代表永不过期
timeout: 2592000 timeout: 2592000
# token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: -1 activity-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) # 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false is-share: true
# token风格 # token风格
token-style: uuid token-style: uuid
# 是否输出操作日志 # 是否输出操作日志
is-log: false is-log: false
``` ```
如果你习惯于 `application.properties` 类型配置文件,那也很好办: <br> <!------------- tab:application.properties 风格 ------------->
百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) ``` java
server:
# 端口
port: 8081
############## Sa-Token 配置 ##############
# token名称 (同时也是cookie名称)
sa-token.token-name=satoken
# token有效期单位s 默认30天, -1代表永不过期
sa-token.timeout=2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
sa-token.activity-timeout=-1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
sa-token.is-concurrent=true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
sa-token.is-share=true
# token风格
sa-token.token-style=uuid
# 是否输出操作日志
sa-token.is-log=false
```
<!---------------------------- tabs:end ------------------------------>
### 4、创建启动类 ### 4、创建启动类

View File

@@ -166,7 +166,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
/* 调整表格的响应式 */ /* 调整表格的响应式 */
#main table{margin-left: 0px;} #main table{margin-left: 0px;}
@media screen and (min-width: 800px) { @media screen and (min-width: 800px) {
#main table tr th{min-width: 150px;} #main table tr th{min-width: 100px;}
} }
/* 提示框加上灰色背景 */ /* 提示框加上灰色背景 */
@@ -255,6 +255,8 @@ body {
padding: 8px 14px; padding: 8px 14px;
font-size: 14px; font-size: 14px;
transition: all 0.15s; transition: all 0.15s;
text-decoration: none !important;
font-weight: 400;
/* 背景 */ /* 背景 */
background-image: url(icon/dati.svg); background-image: url(icon/dati.svg);

View File

@@ -1,7 +1,7 @@
# Sa-Token 集成 Redis # Sa-Token 集成 Redis
--- ---
Sa-token 默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如: Sa-Token 默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如:
1. 重启后数据会丢失。 1. 重启后数据会丢失。
2. 无法在分布式环境中共享数据。 2. 无法在分布式环境中共享数据。

View File

@@ -58,14 +58,14 @@ public String add() {
public SaResult deleteProject(String projectId) { public SaResult deleteProject(String projectId) {
// 第1步先检查当前会话是否已完成二级认证 // 第1步先检查当前会话是否已完成二级认证
if(!StpUtil.isSafe()) { if(!StpUtil.isSafe()) {
return SaResult.error("请完成二级认证后再次访问接口"); return SaResult.error("仓库删除失败,请完成二级认证后再次访问接口");
} }
// 第2步如果已完成二级认证则开始执行业务逻辑 // 第2步如果已完成二级认证则开始执行业务逻辑
// ... // ...
// 第3步返回结果 // 第3步返回结果
return SaResult.ok(); return SaResult.ok("仓库删除成功");
} }
// 提供密码进行二级认证 // 提供密码进行二级认证
@@ -86,9 +86,16 @@ public SaResult openSafe(String password) {
调用步骤: 调用步骤:
1. 前端调用 `deleteProject` 接口,尝试删除仓库。 1. 前端调用 `deleteProject` 接口,尝试删除仓库。
2. 后端校验会话尚未完成二级认证,返回: `请完成二级认证后再次访问接口`。 2. 后端校验会话尚未完成二级认证,返回: `仓库删除失败,请完成二级认证后再次访问接口`。
3. 前端将信息提示给用户,用户输入密码,调用 `openSafe` 接口。 3. 前端将信息提示给用户,用户输入密码,调用 `openSafe` 接口。
4. 后端比对用户输入的密码完成二级认证有效期为120秒。 4. 后端比对用户输入的密码完成二级认证有效期为120秒。
5. 前端在 120 秒内再次调用 `deleteProject` 接口,尝试删除仓库。 5. 前端在 120 秒内再次调用 `deleteProject` 接口,尝试删除仓库。
6. 后端校验会话已完成二级认证,仓库删除成功。 6. 后端校验会话已完成二级认证,返回:`仓库删除成功`
---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/SafeAuthController.java"
target="_blank">
本章代码示例Sa-Token 二级认证 —— [ com.pj.cases.up.SafeAuthController.java ]
</a>

View File

@@ -1,11 +1,7 @@
# 注解鉴权 # 注解鉴权
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/AtCheckController.java"
target="_blank">
本章代码示例Sa-Token 注解鉴权 —— [ com.pj.cases.AtCheckController.java ]
</a>
--- ### 注解鉴权
有同学表示:尽管使用代码鉴权非常方便,但是我仍希望把鉴权逻辑和业务逻辑分离开来,我可以使用注解鉴权吗?当然可以!<br> 有同学表示:尽管使用代码鉴权非常方便,但是我仍希望把鉴权逻辑和业务逻辑分离开来,我可以使用注解鉴权吗?当然可以!<br>
@@ -162,6 +158,11 @@ public class TestController {
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/use/AtCheckController.java"
target="_blank">
本章代码示例Sa-Token 注解鉴权 —— [ com.pj.cases.use.AtCheckController.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/ARJvIbA/" target="_blank">本章小练习Sa-Token 基础 - 注解鉴权,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/ARJvIbA/" target="_blank">本章小练习Sa-Token 基础 - 注解鉴权,章节测试</a>

View File

@@ -1,15 +1,17 @@
# 框架配置 # 框架配置
你可以**零配置启动框架** <br>
但同时你也可以通过配置,定制性使用框架,`Sa-Token`支持多种方式配置框架信息
你可以**零配置启动框架**,但同时你也可以通过一定的参数配置,定制性使用框架,`Sa-Token`支持多种方式配置框架信息
---
### 方式1、在 application.yml 配置 ### 方式1、在 application.yml 配置
<!------------------------------ tabs:start ------------------------------>
<!------------- tab:application.yml 风格 ------------->
``` java ``` java
# Sa-Token 配置 ############## Sa-Token 配置 ##############
############## 在线参考https://sa-token.dev33.cn/doc.html#/use/config ##############
sa-token: sa-token:
# token名称 (同时也是cookie名称) # token名称 (同时也是cookie名称)
token-name: satoken token-name: satoken
@@ -27,19 +29,42 @@ sa-token:
is-log: false is-log: false
``` ```
如果你习惯于 `application.properties` 类型的配置文件,那也很好办: 百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) <!------------- tab:application.properties 风格 ------------->
``` java
############## Sa-Token 配置 ##############
############## 在线参考https://sa-token.dev33.cn/doc.html#/use/config ##############
# token名称 (同时也是cookie名称)
sa-token.token-name=satoken
# token有效期单位s 默认30天, -1代表永不过期
sa-token.timeout=2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
sa-token.activity-timeout=-1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
sa-token.is-concurrent=true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
sa-token.is-share=true
# token风格
sa-token.token-style=uuid
# 是否输出操作日志
sa-token.is-log=false
```
<!---------------------------- tabs:end ------------------------------>
### 方式2、通过代码配置 ### 方式2、通过代码配置
模式1
<!------------------------------ tabs:start ------------------------------>
<!------------- tab:模式 1 ------------->
``` java ``` java
/** /**
* Sa-Token代码方式进行配置 * Sa-Token代码方式进行配置
*/ */
@Configuration @Configuration
public class SaTokenConfigure { public class SaTokenConfigure {
// 获取配置Bean (以代码的方式配置Sa-Token, 此配置会覆盖 application.yml 中的配置)
// 获取配置Bean (以代码的方式配置Sa-Token, 此配置会覆盖yml中的配置)
@Bean @Bean
@Primary @Primary
public SaTokenConfig getSaTokenConfigPrimary() { public SaTokenConfig getSaTokenConfigPrimary() {
@@ -53,21 +78,36 @@ public class SaTokenConfigure {
config.setIsLog(false); // 是否输出操作日志 config.setIsLog(false); // 是否输出操作日志
return config; return config;
} }
} }
``` ```
<!------------- tab:模式 2 ------------->
模式2
``` java ``` java
// 以代码的方式配置Sa-Token-Config /**
@Autowired * Sa-Token代码方式进行配置
public void configSaToken(SaTokenConfig config) { */
// config.setTokenName("satoken333"); // token名称 (同时也是cookie名称) @Configuration
// ... public class SaTokenConfigure {
// 以代码的方式配置 SaTokenConfig
// 此配置会与 application.yml 中的配置合并 (代码配置优先)
@Autowired
public void configSaToken(SaTokenConfig config) {
SaTokenConfig config = new SaTokenConfig();
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
config.setTimeout(30 * 24 * 60 * 60); // token有效期单位s 默认30天
config.setActivityTimeout(-1); // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
config.setIsConcurrent(true); // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
config.setIsShare(true); // 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
config.setTokenStyle("uuid"); // token风格
config.setIsLog(false); // 是否输出操作日志
return config;
}
} }
``` ```
<!---------------------------- tabs:end ------------------------------>
PS两者的区别在于:**`模式1会覆盖yml中的配置模式2会与yml中的配置合并`** 两者的区别在于:
- 模式 1 会覆盖 application.yml 中的配置。
- 模式 2 会与 application.yml 中的配置合并(代码配置优先)。
--- ---

View File

@@ -1,10 +1,5 @@
# 权限认证 # 权限认证
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/JurAuthController.java"
target="_blank">
本章代码示例Sa-Token 权限认证 —— [ com.pj.cases.JurAuthController.java ]
</a>
--- ---
@@ -196,4 +191,9 @@ StpUtil.hasPermission("index.html"); // false
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/use/JurAuthController.java"
target="_blank">
本章代码示例Sa-Token 权限认证 —— [ com.pj.cases.use.JurAuthController.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/ZfIjYr9/" target="_blank">本章小练习Sa-Token 基础 - 权限认证,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/ZfIjYr9/" target="_blank">本章小练习Sa-Token 基础 - 权限认证,章节测试</a>

View File

@@ -1,14 +1,5 @@
# 踢人下线 # 踢人下线
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/KickoutController.java"
target="_blank">
本章代码示例Sa-Token 踢人下线 —— [ com.pj.cases.KickoutController.java ]
</a>
---
### 设计思路
所谓踢人下线,核心操作就是找到指定 `loginId` 对应的 `Token`,并设置其失效。 所谓踢人下线,核心操作就是找到指定 `loginId` 对应的 `Token`,并设置其失效。
![踢下线](https://oss.dev33.cn/sa-token/doc/kickout.png) ![踢下线](https://oss.dev33.cn/sa-token/doc/kickout.png)
@@ -40,6 +31,11 @@ StpUtil.kickoutByTokenValue("token"); // 将指定 Token 踢下线
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/use/KickoutController.java"
target="_blank">
本章代码示例Sa-Token 踢人下线 —— [ com.pj.cases.use.KickoutController.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/MFNN7bK/" target="_blank">本章小练习Sa-Token 基础 - 踢人下线,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/MFNN7bK/" target="_blank">本章小练习Sa-Token 基础 - 踢人下线,章节测试</a>

View File

@@ -1,10 +1,5 @@
# 登录认证 # 登录认证
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/LoginAuthController.java"
target="_blank">
本章代码示例Sa-Token 登录认证 —— [ com.pj.cases.LoginAuthController.java ]
</a>
--- ---
@@ -175,5 +170,10 @@ public class LoginController {
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/use/LoginAuthController.java"
target="_blank">
本章代码示例Sa-Token 登录认证 —— [ com.pj.cases.use.LoginAuthController.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/UZBZJvb2ej/" target="_blank">本章小练习Sa-Token 基础 - 登录认证,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/UZBZJvb2ej/" target="_blank">本章小练习Sa-Token 基础 - 登录认证,章节测试</a>

View File

@@ -1,4 +1,5 @@
# 路由拦截鉴权 # 路由拦截鉴权
--- ---
假设我们有如下需求: 假设我们有如下需求:
@@ -41,6 +42,12 @@ public class SaTokenConfigure implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,定义详细认证规则 // 注册 Sa-Token 拦截器,定义详细认证规则
registry.addInterceptor(new SaInterceptor(handler -> { registry.addInterceptor(new SaInterceptor(handler -> {
// 指定一条 match 规则
SaRouter
.match("/**") // 拦截的 path 列表,可以写多个
.notMatch("/user/doLogin") // 排除掉的 path 列表,可以写多个
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式
// 根据路由划分模块,不同模块不同鉴权 // 根据路由划分模块,不同模块不同鉴权
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
@@ -68,13 +75,13 @@ public class SaTokenConfigure implements WebMvcConfigurer {
// 注册路由拦截器,自定义认证规则 // 注册路由拦截器,自定义认证规则
registry.addInterceptor(new SaInterceptor(handler -> { registry.addInterceptor(new SaInterceptor(handler -> {
// 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin()); SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
// 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证 // 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin")); SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
// 权限认证 -- 不同模块认证不同权限 // 权限校验 -- 不同模块校验不同权限
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods")); SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
@@ -227,6 +234,11 @@ public void addInterceptors(InterceptorRegistry registry) {
``` ```
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaTokenConfigure.java"
target="_blank">
本章代码示例Sa-Token 路由拦截鉴权 —— [ com.pj.satoken.SaTokenConfigure.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/rY7VFv/" target="_blank">本章小练习Sa-Token 基础 - 路由拦截鉴权,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/rY7VFv/" target="_blank">本章小练习Sa-Token 基础 - 路由拦截鉴权,章节测试</a>

View File

@@ -1,4 +1,5 @@
# Session会话 # Session会话
--- ---
### Session是什么 ### Session是什么
@@ -169,5 +170,10 @@ StpUtil.getAnonTokenSession();
--- ---
<a class="case-btn" href="https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaSessionController.java"
target="_blank">
本章代码示例Sa-Token Session 会话 —— [ com.pj.cases.use.SaSessionController.java ]
</a>
<a class="dt-btn" href="https://www.wenjuan.ltd/s/MNnUr2V/" target="_blank">本章小练习Sa-Token 基础 - Session 会话,章节测试</a> <a class="dt-btn" href="https://www.wenjuan.ltd/s/MNnUr2V/" target="_blank">本章小练习Sa-Token 基础 - Session 会话,章节测试</a>