文章目录
1. Sa-Token 踢人下线
- Sa-Token官方文档链接: Sa-Token 踢人下线
- 踢人下线核心操作就是找到指定
**loginId**
对应的**Token**
,并设置其失效。
强制注销 和 踢人下线 的区别在于:
- 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
- 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
1. 强制注销
StpUtil.logout(10001); // 强制指定账号注销下线
StpUtil.logout(10001, "PC"); // 强制指定账号指定端注销下线
StpUtil.logoutByTokenValue("token"); // 强制指定 Token 注销下线
2. 踢人下线
StpUtil.kickout(10001); // 将指定账号踢下线
StpUtil.kickout(10001, "PC"); // 将指定账号指定端踢下线
StpUtil.kickoutByTokenValue("token"); // 将指定 Token 踢下线
3. 测试小demo
package com.ccovo.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.ccovo.domain.R;
import com.ccovo.domain.constants.Constants;
import com.ccovo.enums.ErrorCode;
import com.ccovo.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Api(tags = "踢人下线接口")
@RequestMapping("/kictout")
public class KickoutController {
/**
* 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
* 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
*/
/**
* 强制指定账号注销下线
*/
@ApiOperation(value = "强制指定账号注销下线")
@PostMapping("/logout")
public R<?> logout(Long loginId) {
StpUtil.logout(loginId);
return R.ok();
}
/**
* 强制指定账号指定端注销下线
*/
@ApiOperation(value = "强制指定账号指定端注销下线")
@PostMapping("/logoutByLoginKey")
public R<?> logoutByLoginKey(Long loginId, String device) {
StpUtil.logout(loginId, device);
return R.ok();
}
/**
* 指定Token注销下线
*/
@ApiOperation(value = "指定Token注销下线")
@PostMapping("/logoutByTokenValue")
public R<?> logoutByTokenValue(String tokenValue) {
StpUtil.logoutByTokenValue(tokenValue);
return R.ok();
}
/**
* 指定账号踢下线
*/
@ApiOperation(value = "指定账号踢下线")
@PostMapping("/kickout")
public R<?> kickout(Long loginId) {
StpUtil.kickout(loginId);
return R.ok();
}
/**
* 指定账号指定端踢下线
*/
@ApiOperation(value = "指定账号指定端踢下线")
@PostMapping("/kickoutByLoginKey")
public R<?> kickoutByLoginKey(Long loginId, String device) {
StpUtil.kickout(loginId, device);
return R.ok();
}
/**
* 指定Token踢下线
*/
@ApiOperation(value = "指定Token踢下线")
@PostMapping("/kickoutByTokenValue")
public R<?> kickoutByTokenValue(String tokenValue) {
StpUtil.kickoutByTokenValue(tokenValue);
return R.ok();
}
}
2. Sa-Token 注解鉴权
- Sa-Token官方文档链接: Sa-Token 注解鉴权
注解鉴权 —— 优雅的将鉴权与业务代码分离!
@SaCheckLogin
: 登录校验 —— 只有登录之后才能进入该方法。@SaCheckRole("admin")
: 角色校验 —— 必须具有指定角色标识才能进入该方法。@SaCheckPermission("user:add")
: 权限校验 —— 必须具有指定权限才能进入该方法。@SaCheckSafe
: 二级认证校验 —— 必须二级认证之后才能进入该方法。@SaCheckHttpBasic
: HttpBasic校验 —— 只有通过 HttpBasic 认证后才能进入该方法。@SaCheckHttpDigest
: HttpDigest校验 —— 只有通过 HttpDigest 认证后才能进入该方法。@SaIgnore
:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。@SaCheckDisable("comment")
:账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。
1. 注册拦截器
package com.ccovo.config.satoken;
import cn.dev33.satoken.interceptor.SaInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
// 拦截除了 /user/doLogin 的所有请求,并且需要用户已登录才可放行
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// // 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。
// registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
// .addPathPatterns("/**")
// // 放行接口文档相关路径
// .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**",
// "/api", "/api-docs", "/api-docs/**", "/doc.html*", "/doc.html#/**")
// .excludePathPatterns("/login");
// }
}
2. 使用注解鉴权
- 以下注解都可以加在类上,代表为这个类所有方法进行鉴权
// 登录校验:只有登录之后才能进入该方法
@SaCheckLogin
@RequestMapping("info")
public String info() {
return "查询用户信息";
}
// 角色校验:必须具有指定角色才能进入该方法
@SaCheckRole("super-admin")
@RequestMapping("add")
public String add() {
return "用户增加";
}
// 权限校验:必须具有指定权限才能进入该方法
@SaCheckPermission("user-add")
@RequestMapping("add")
public String add() {
return "用户增加";
}
// 二级认证校验:必须二级认证之后才能进入该方法
@SaCheckSafe()
@RequestMapping("add")
public String add() {
return "用户增加";
}
// Http Basic 校验:只有通过 Http Basic 认证后才能进入该方法
@SaCheckHttpBasic(account = "sa:123456")
@RequestMapping("add")
public String add() {
return "用户增加";
}
// Http Digest 校验:只有通过 Http Digest 认证后才能进入该方法
@SaCheckHttpDigest(value = "sa:123456")
@RequestMapping("add")
public String add() {
return "用户增加";
}
// 校验当前账号是否被封禁 comment 服务,如果已被封禁会抛出异常,无法进入方法
@SaCheckDisable("comment")
@RequestMapping("send")
public String send() {
return "查询用户信息";
}
3. 设定校验模式
@SaCheckRole
与@SaCheckPermission
注解可设置校验模式,例如:SaMode.AND
,标注一组权限,会话必须全部具有才可通过校验。SaMode.OR
,标注一组权限,会话只要具有其一即可通过校验。
// 注解式鉴权:只要具有其中一个权限即可通过校验
@RequestMapping("atJurOr")
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR)
public SaResult atJurOr() {
return SaResult.data("用户信息");
}
// 注解式鉴权:满足所有权限即可通过校验
@RequestMapping("atJurAnd")
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.AND)
public SaResult atJurAnd() {
return SaResult.data("用户信息");
}
4. 角色权限双重OR校验
orRole 代表权限校验未通过时的次要选择,两者只要其一校验成功即可进入请求方法,其有三种写法:
- 写法一:
orRole = "admin"
,代表需要拥有角色 admin 。 - 写法二:
orRole = {"admin", "manager", "staff"}
,代表具有三个角色其一即可。 - 写法三:
orRole = {"admin, manager, staff"}
,代表必须同时具有三个角色。
// 角色权限双重 “or校验”:具备指定权限或者指定角色即可通过校验
@RequestMapping("userAdd")
@SaCheckPermission(value = "user.add", orRole = "admin")
public SaResult userAdd() {
return SaResult.data("用户信息");
}
5. 忽略认证
- @SaIgnore 修饰方法时代表方法可以被游客访问,修饰类时代表类中的所有接口都可以游客访问。
- @SaIgnore 有最高优先级,当 @SaIgnore 和其它鉴权注解一起出现时,其它鉴权注解都将被忽略。
- @SaIgnore 可以忽略掉 Sa-Token 拦截器中的路由鉴权。
@SaCheckLogin
@RestController
public class TestController {
// ... 其它方法
// 此接口加上了 @SaIgnore 可以游客访问
@SaIgnore
@RequestMapping("getList")
public SaResult getList() {
// ...
return SaResult.ok();
}
}
6. 批量注解鉴权
// 在 `@SaCheckOr` 中可以指定多个注解,只要当前会话满足其中一个注解即可通过验证,进入方法。
@SaCheckOr(
login = @SaCheckLogin,
role = @SaCheckRole("admin"),
permission = @SaCheckPermission("user.add"),
safe = @SaCheckSafe("update-password"),
httpBasic = @SaCheckHttpBasic(account = "sa:123456"),
disable = @SaCheckDisable("submit-orders")
)
@RequestMapping("test")
public SaResult test() {
// ...
return SaResult.ok();
}
7. 测试小demo
package com.ccovo.controller;
import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.stp.StpUtil;
import com.ccovo.domain.R;
import com.ccovo.domain.constants.Constants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Api(tags = "注解鉴权接口")
@RequestMapping("/annotation_auth")
public class AnnotationAuthController {
/**
* @SaCheckLogin: 登录校验 —— 只有登录之后才能进入该方法。
* @SaCheckRole("admin"): 角色校验 —— 必须具有指定角色标识才能进入该方法。
* @SaCheckPermission("user:add"): 权限校验 —— 必须具有指定权限才能进入该方法。
* @SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法。
* @SaCheckHttpBasic: HttpBasic校验 —— 只有通过 HttpBasic 认证后才能进入该方法。
* @SaCheckHttpDigest: HttpDigest校验 —— 只有通过 HttpDigest 认证后才能进入该方法。
* @SaIgnore:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。
* @SaCheckDisable("comment"):账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。
*/
/**
* 登录校验
*/
@ApiOperation(value = "登录校验")
@PostMapping("/checkLogin")
@SaCheckLogin
public R<?> checkLogin() {
return R.ok();
}
/**
* 角色校验
*/
@ApiOperation(value = "角色校验")
@PostMapping("/checkRole")
@SaCheckRole(Constants.ADMIN)
public R<?> checkRole() {
return R.ok();
}
/**
* 权限校验
*/
@ApiOperation(value = "权限校验")
@PostMapping("/checkPermission")
@SaCheckPermission("user.add")
public R<?> checkPermission() {
return R.ok();
}
/**
* 二级认证校验
*/
@ApiOperation(value = "二级认证校验")
@PostMapping("/checkSafe")
@SaCheckSafe()
public R<?> checkSafe() {
return R.ok();
}
/**
* Http Basic 校验
*/
@ApiOperation(value = "Http Basic 校验")
@PostMapping("/checkHttpBasic")
// 账号密码:sa:123456
@SaCheckHttpBasic(account = "sa:123456")
public R<?> checkHttpBasic() {
return R.ok();
}
/**
* Http Digest 校验
*/
@ApiOperation(value = "Http Digest 校验")
@PostMapping("/checkHttpDigest")
// 账号密码:sa:123456
@SaCheckHttpDigest(value = "sa:123456")
public R<?> checkHttpDigest() {
return R.ok();
}
/**
* 校验当前账号是否封禁"comment"服务
*/
@ApiOperation(value = "校验当前账号是否封禁\"comment\"服务")
@PostMapping("/checkDisable")
@SaCheckDisable("comment")
public R<?> checkDisable() {
return R.ok();
}
/**
* 权限校验(OR)
*/
@ApiOperation(value = "权限校验(OR)")
@PostMapping("/checkPermissionOr")
@SaCheckPermission(value = {"user.add", "user.edit"}, mode = SaMode.OR)
public R<?> checkPermissionOr() {
return R.ok();
}
/**
* 权限校验(AND)
*/
@ApiOperation(value = "权限校验(AND)")
@PostMapping("/checkPermissionAnd")
@SaCheckPermission(value = {"user.add", "user.edit"}, mode = SaMode.AND)
public R<?> checkPermissionAnd() {
return R.ok();
}
/**
* 角色权限双重OR校验
* orRole 字段代表权限校验未通过时的次要选择,两者只要其一校验成功即可进入请求方法,其有三种写法:
* 写法一:orRole = "admin",代表需要拥有角色 admin 。
* 写法二:(OR) orRole = {"admin", "manager", "staff"},代表具有三个角色其一即可。
* 写法三:(AND) orRole = {"admin, manager, staff"},代表必须同时具有三个角色。
*/
@ApiOperation(value = "角色权限双重OR校验")
@PostMapping("/checkPermissionOrRole")
@SaCheckPermission(value = "user.add", orRole = Constants.ADMIN)
public R<?> checkRoleOr() {
return R.ok();
}
/**
* 忽略认证
* @SaIgnore 修饰方法时代表这个方法可以被游客访问,修饰类时代表这个类中的所有接口都可以游客访问。
* @SaIgnore 具有最高优先级,当 @SaIgnore 和其它鉴权注解一起出现时,其它鉴权注解都将被忽略。
* @SaIgnore 同样可以忽略掉 Sa-Token 拦截器中的路由鉴权
*/
@ApiOperation(value = "忽略认证")
@PostMapping("/ignore")
@SaIgnore
public R<?> ignore() {
return R.ok();
}
/**
* 批量注解鉴权
*/
@ApiOperation(value = "批量注解鉴权")
@PostMapping("/batch")
@SaCheckOr(
login = @SaCheckLogin,
role = @SaCheckRole(Constants.ADMIN),
permission = @SaCheckPermission("user.add"),
safe = @SaCheckSafe("update-password"),
httpBasic = @SaCheckHttpBasic(account = "sa:123456"),
disable = @SaCheckDisable("submit-orders")
)
public R<?> batch() {
return R.ok();
}
}
eturn R.ok();
}
/**
* 批量注解鉴权
*/
@ApiOperation(value = "批量注解鉴权")
@PostMapping("/batch")
@SaCheckOr(
login = @SaCheckLogin,
role = @SaCheckRole(Constants.ADMIN),
permission = @SaCheckPermission("user.add"),
safe = @SaCheckSafe("update-password"),
httpBasic = @SaCheckHttpBasic(account = "sa:123456"),
disable = @SaCheckDisable("submit-orders")
)
public R<?> batch() {
return R.ok();
}
}