mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-05-14 12:52:08 +08:00
新增代码示例
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package com.pj.cases;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/jur/")
|
||||
public class JurAuthController {
|
||||
|
||||
/*
|
||||
* 前提1:首先调用登录接口进行登录,代码在 com.pj.cases.LoginAuthController 中有详细解释,此处不再赘述
|
||||
* ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
|
||||
*
|
||||
* 前提2:项目实现 StpInterface 接口,代码在 com.pj.satoken.StpInterfaceImpl
|
||||
* Sa-Token 将从此实现类获取 每个账号拥有哪些权限。
|
||||
*
|
||||
* 然后我们就可以使用以下示例中的代码进行鉴权了
|
||||
*/
|
||||
|
||||
// 查询权限 ---- http://localhost:8081/jur/getPermission
|
||||
@RequestMapping("getPermission")
|
||||
public SaResult getPermission() {
|
||||
// 查询权限信息 ,如果当前会话未登录,会返回一个空集合
|
||||
List<String> permissionList = StpUtil.getPermissionList();
|
||||
System.out.println("当前登录账号拥有的所有权限:" + permissionList);
|
||||
|
||||
// 查询角色信息 ,如果当前会话未登录,会返回一个空集合
|
||||
List<String> roleList = StpUtil.getRoleList();
|
||||
System.out.println("当前登录账号拥有的所有角色:" + roleList);
|
||||
|
||||
// 返回给前端
|
||||
return SaResult.ok()
|
||||
.set("roleList", roleList)
|
||||
.set("permissionList", permissionList);
|
||||
}
|
||||
|
||||
// 权限校验 ---- http://localhost:8081/jur/checkPermission
|
||||
@RequestMapping("checkPermission")
|
||||
public SaResult checkPermission() {
|
||||
|
||||
// 判断:当前账号是否拥有一个权限,返回 true 或 false
|
||||
// 如果当前账号未登录,则永远返回 false
|
||||
StpUtil.hasPermission("user.add");
|
||||
StpUtil.hasPermissionAnd("user.add", "user.delete", "user.get"); // 指定多个,必须全部拥有才会返回 true
|
||||
StpUtil.hasPermissionOr("user.add", "user.delete", "user.get"); // 指定多个,只要拥有一个就会返回 true
|
||||
|
||||
// 校验:当前账号是否拥有一个权限,校验不通过时会抛出 `NotPermissionException` 异常
|
||||
// 如果当前账号未登录,则永远校验失败
|
||||
StpUtil.checkPermission("user.add");
|
||||
StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get"); // 指定多个,必须全部拥有才会校验通过
|
||||
StpUtil.checkPermissionOr("user.add", "user.delete", "user.get"); // 指定多个,只要拥有一个就会校验通过
|
||||
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
// 角色校验 ---- http://localhost:8081/jur/checkRole
|
||||
@RequestMapping("checkRole")
|
||||
public SaResult checkRole() {
|
||||
|
||||
// 判断:当前账号是否拥有一个角色,返回 true 或 false
|
||||
// 如果当前账号未登录,则永远返回 false
|
||||
StpUtil.hasRole("admin");
|
||||
StpUtil.hasRoleAnd("admin", "ceo", "cfo"); // 指定多个,必须全部拥有才会返回 true
|
||||
StpUtil.hasRoleOr("admin", "ceo", "cfo"); // 指定多个,只要拥有一个就会返回 true
|
||||
|
||||
// 校验:当前账号是否拥有一个角色,校验不通过时会抛出 `NotRoleException` 异常
|
||||
// 如果当前账号未登录,则永远校验失败
|
||||
StpUtil.checkRole("admin");
|
||||
StpUtil.checkRoleAnd("admin", "ceo", "cfo"); // 指定多个,必须全部拥有才会校验通过
|
||||
StpUtil.checkRoleOr("admin", "ceo", "cfo"); // 指定多个,只要拥有一个就会校验通过
|
||||
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
// 权限通配符 ---- http://localhost:8081/jur/wildcardPermission
|
||||
@RequestMapping("wildcardPermission")
|
||||
public SaResult wildcardPermission() {
|
||||
|
||||
// 前提条件:在 StpInterface 实现类中,为账号返回了 "art.*" 泛权限
|
||||
StpUtil.hasPermission("art.add"); // 返回 true
|
||||
StpUtil.hasPermission("art.delete"); // 返回 true
|
||||
StpUtil.hasPermission("goods.add"); // 返回 false,因为前缀不符合
|
||||
|
||||
// * 符合可以出现在任意位置,比如权限码的开头,当账号拥有 "*.delete" 时
|
||||
StpUtil.hasPermission("goods.add"); // false
|
||||
StpUtil.hasPermission("goods.delete"); // true
|
||||
StpUtil.hasPermission("art.delete"); // true
|
||||
|
||||
// 也可以出现在权限码的中间,比如当账号拥有 "shop.*.user" 时
|
||||
StpUtil.hasPermission("shop.add.user"); // true
|
||||
StpUtil.hasPermission("shop.delete.user"); // true
|
||||
StpUtil.hasPermission("shop.delete.goods"); // false,因为后缀不符合
|
||||
|
||||
// 注意点:
|
||||
// 1、上帝权限:当一个账号拥有 "*" 权限时,他可以验证通过任何权限码
|
||||
// 2、角色校验也可以加 * ,指定泛角色,例如: "*.admin",暂不赘述
|
||||
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.pj.cases;
|
||||
|
||||
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-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/kickout/")
|
||||
public class KickoutController {
|
||||
|
||||
/*
|
||||
* 前提:首先调用登录接口进行登录,代码在 com.pj.cases.LoginAuthController 中有详细解释,此处不再赘述
|
||||
*/
|
||||
|
||||
// 将指定账号强制注销 ---- http://localhost:8081/kickout/logout?userId=10001
|
||||
@RequestMapping("logout")
|
||||
public SaResult logout(long userId) {
|
||||
|
||||
// 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
|
||||
StpUtil.logout(userId);
|
||||
|
||||
// 返回
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
// 将指定账号踢下线 ---- http://localhost:8081/kickout/kickout?userId=10001
|
||||
@RequestMapping("kickout")
|
||||
public SaResult kickout(long userId) {
|
||||
|
||||
// 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
|
||||
StpUtil.kickout(userId);
|
||||
|
||||
// 返回
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
/*
|
||||
* 你可以分别在强制注销和踢人下线后,再次访问一下登录校验接口,对比一下两者返回的提示信息有何不同
|
||||
* ---- http://localhost:8081/acc/checkLogin
|
||||
*/
|
||||
|
||||
// 根据 Token 值踢人 ---- http://localhost:8081/kickout/kickoutByTokenValue?tokenValue=xxxx-xxxx-xxxx-xxxx已登录账号的token值
|
||||
public SaResult kickoutByTokenValue(String tokenValue) {
|
||||
|
||||
StpUtil.kickoutByTokenValue(tokenValue);
|
||||
|
||||
// 返回
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,47 +3,137 @@ package com.pj.cases;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
* 登录认证示例
|
||||
* Sa-Token 登录认证示例
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
* @since 2022-10-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/acc/")
|
||||
public class LoginAuthController {
|
||||
|
||||
// 测试登录 ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
|
||||
// 会话登录接口 ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
|
||||
@RequestMapping("doLogin")
|
||||
public SaResult doLogin(String name, String pwd) {
|
||||
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
|
||||
|
||||
// 第一步:比对前端提交的 账号名称 & 密码 是否正确,比对成功后开始登录
|
||||
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
|
||||
if("zhang".equals(name) && "123456".equals(pwd)) {
|
||||
|
||||
// 第二步:根据账号id,进行登录
|
||||
// 此处填入的参数应该保持用户表唯一,比如用户id,不可以直接填入整个 User 对象
|
||||
StpUtil.login(10001);
|
||||
|
||||
// SaResult 是 Sa-Token 中对返回结果的简单封装,下面的示例将不再赘述
|
||||
return SaResult.ok("登录成功");
|
||||
}
|
||||
|
||||
return SaResult.error("登录失败");
|
||||
}
|
||||
|
||||
// 查询登录状态 ---- http://localhost:8081/acc/isLogin
|
||||
// 查询当前登录状态 ---- http://localhost:8081/acc/isLogin
|
||||
@RequestMapping("isLogin")
|
||||
public SaResult isLogin() {
|
||||
return SaResult.ok("是否登录:" + StpUtil.isLogin());
|
||||
// StpUtil.isLogin() 查询当前客户端是否登录,返回 true 或 false
|
||||
boolean isLogin = StpUtil.isLogin();
|
||||
return SaResult.ok("当前客户端是否登录:" + isLogin);
|
||||
}
|
||||
|
||||
// 校验当前登录状态 ---- http://localhost:8081/acc/checkLogin
|
||||
@RequestMapping("checkLogin")
|
||||
public SaResult checkLogin() {
|
||||
// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
|
||||
StpUtil.checkLogin();
|
||||
|
||||
// 抛出异常后,代码将走入全局异常处理(GlobalException.java),如果没有抛出异常,则代表通过了登录校验,返回下面信息
|
||||
return SaResult.ok("校验登录成功,这行字符串是只有登录后才会返回的信息");
|
||||
}
|
||||
|
||||
// 获取当前登录的账号是谁 ---- http://localhost:8081/acc/getLoginId
|
||||
@RequestMapping("getLoginId")
|
||||
public SaResult getLoginId() {
|
||||
// 需要注意的是,StpUtil.getLoginId() 自带登录校验效果
|
||||
// 也就是说如果在未登录的情况下调用这句代码,框架就会抛出 `NotLoginException` 异常,效果和 StpUtil.checkLogin() 是一样的
|
||||
Object userId = StpUtil.getLoginId();
|
||||
System.out.println("当前登录的账号id是:" + userId);
|
||||
|
||||
// 如果不希望 StpUtil.getLoginId() 触发登录校验效果,可以填入一个默认值
|
||||
// 如果会话未登录,则返回这个默认值,如果会话已登录,将正常返回登录的账号id
|
||||
Object userId2 = StpUtil.getLoginId(0);
|
||||
System.out.println("当前登录的账号id是:" + userId2);
|
||||
|
||||
// 或者使其在未登录的时候返回 null
|
||||
Object userId3 = StpUtil.getLoginIdDefaultNull();
|
||||
System.out.println("当前登录的账号id是:" + userId3);
|
||||
|
||||
// 类型转换:
|
||||
// StpUtil.getLoginId() 返回的是 Object 类型,你可以使用以下方法指定其返回的类型
|
||||
int userId4 = StpUtil.getLoginIdAsInt(); // 将返回值转换为 int 类型
|
||||
long userId5 = StpUtil.getLoginIdAsLong(); // 将返回值转换为 long 类型
|
||||
String userId6 = StpUtil.getLoginIdAsString(); // 将返回值转换为 String 类型
|
||||
|
||||
// 疑问:数据基本类型不是有八个吗,为什么只封装以上三种类型的转换?
|
||||
// 因为大多数项目都是拿 int、long 或 String 声明 UserId 的类型的,实在没见过哪个项目用 double、float、boolean 之类来声明 UserId
|
||||
System.out.println("当前登录的账号id是:" + userId4 + " --- " + userId5 + " --- " + userId6);
|
||||
|
||||
// 返回给前端
|
||||
return SaResult.ok("当前客户端登录的账号id是:" + userId);
|
||||
}
|
||||
|
||||
// 查询 Token 信息 ---- http://localhost:8081/acc/tokenInfo
|
||||
@RequestMapping("tokenInfo")
|
||||
public SaResult tokenInfo() {
|
||||
// TokenName 是 Token 名称的意思,此值也决定了前端提交 Token 时应该使用的参数名称
|
||||
String tokenName = StpUtil.getTokenName();
|
||||
System.out.println("前端提交 Token 时应该使用的参数名称:" + tokenName);
|
||||
|
||||
// 使用 StpUtil.getTokenValue() 获取前端提交的 Token 值
|
||||
// 框架默认前端可以从以下三个途径中提交 Token:
|
||||
// Cookie (浏览器自动提交)
|
||||
// Header头 (代码手动提交)
|
||||
// Query 参数 (代码手动提交) 例如: /user/getInfo?satoken=xxxx-xxxx-xxxx-xxxx
|
||||
// 读取顺序为: Query 参数 --> Header头 -- > Cookie
|
||||
// 以上三个地方都读取不到 Token 信息的话,则视为前端没有提交 Token
|
||||
String tokenValue = StpUtil.getTokenValue();
|
||||
System.out.println("前端提交的Token值为:" + tokenValue);
|
||||
|
||||
// TokenInfo 包含了此 Token 的大多数信息
|
||||
SaTokenInfo info = StpUtil.getTokenInfo();
|
||||
System.out.println("Token 名称:" + info.getTokenName());
|
||||
System.out.println("Token 值:" + info.getTokenValue());
|
||||
System.out.println("当前是否登录:" + info.getIsLogin());
|
||||
System.out.println("当前登录的账号id:" + info.getLoginId());
|
||||
System.out.println("当前登录账号的类型:" + info.getLoginType());
|
||||
System.out.println("当前登录客户端的设备类型:" + info.getLoginDevice());
|
||||
System.out.println("当前 Token 的剩余有效期:" + info.getTokenTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
|
||||
System.out.println("当前 Token 的剩余临时有效期:" + info.getTokenActivityTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
|
||||
System.out.println("当前 User-Session 的剩余有效期" + info.getSessionTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
|
||||
System.out.println("当前 Token-Session 的剩余有效期" + info.getTokenSessionTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
|
||||
|
||||
// 返回给前端
|
||||
return SaResult.data(StpUtil.getTokenInfo());
|
||||
}
|
||||
|
||||
// 测试注销 ---- http://localhost:8081/acc/logout
|
||||
// 会话注销 ---- http://localhost:8081/acc/logout
|
||||
@RequestMapping("logout")
|
||||
public SaResult logout() {
|
||||
// 退出登录会清除三个地方的数据:
|
||||
// 1、Redis中保存的 Token 信息
|
||||
// 2、当前请求上下文中保存的 Token 信息
|
||||
// 3、Cookie 中保存的 Token 信息(如果未使用Cookie模式则不会清除)
|
||||
StpUtil.logout();
|
||||
return SaResult.ok();
|
||||
|
||||
// StpUtil.logout() 在未登录时也是可以调用成功的,
|
||||
// 也就是说,无论客户端有没有登录,执行完 StpUtil.logout() 后,都会处于未登录状态
|
||||
System.out.println("当前是否处于登录状态:" + StpUtil.isLogin());
|
||||
|
||||
// 返回给前端
|
||||
return SaResult.ok("退出登录成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.pj.current;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
/**
|
||||
@@ -11,9 +14,9 @@ import cn.dev33.satoken.util.SaResult;
|
||||
@RestControllerAdvice
|
||||
public class GlobalException {
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
// 拦截:未登录异常
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
public SaResult handlerException(NotLoginException e) {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
e.printStackTrace();
|
||||
@@ -21,5 +24,26 @@ public class GlobalException {
|
||||
// 返回给前端
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
// 拦截:缺少权限异常
|
||||
@ExceptionHandler(NotPermissionException.class)
|
||||
public SaResult handlerException(NotPermissionException e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error("缺少权限:" + e.getPermission());
|
||||
}
|
||||
|
||||
// 拦截:缺少角色异常
|
||||
@ExceptionHandler(NotRoleException.class)
|
||||
public SaResult handlerException(NotRoleException e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error("缺少角色:" + e.getRole());
|
||||
}
|
||||
|
||||
// 拦截:其它所有异常
|
||||
@ExceptionHandler(Exception.class)
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@ import org.springframework.stereotype.Component;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
|
||||
/**
|
||||
* 自定义权限验证接口扩展
|
||||
* 自定义权限认证接口扩展,Sa-Token 将从此实现类获取每个账号拥有的权限码
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-13
|
||||
*/
|
||||
@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token的自定义权限验证扩展
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
@@ -21,11 +24,11 @@ public class StpInterfaceImpl implements StpInterface {
|
||||
// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("101");
|
||||
list.add("user-add");
|
||||
list.add("user-delete");
|
||||
list.add("user-update");
|
||||
list.add("user-get");
|
||||
list.add("article-get");
|
||||
list.add("user.add");
|
||||
list.add("user.update");
|
||||
list.add("user.get");
|
||||
// list.add("user.delete");
|
||||
list.add("art.*");
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user