diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/DisableController.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/DisableController.java new file mode 100644 index 00000000..5006a0c8 --- /dev/null +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/DisableController.java @@ -0,0 +1,56 @@ +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-17 + */ +@RestController +@RequestMapping("/disable/") +public class DisableController { + + /* + * 测试步骤: + 1、访问登录接口,可以正常登录 ---- http://localhost:8081/disable/login?userId=10001 + 2、注销登录 ---- http://localhost:8081/disable/logout + 3、禁用账号 ---- http://localhost:8081/disable/disable?userId=10001 + 4、再次访问登录接口,登录失败 ---- http://localhost:8081/disable/login?userId=10001 + */ + + // 会话登录接口 ---- http://localhost:8081/disable/login?userId=10001 + @RequestMapping("login") + public SaResult login(long userId) { + // 1、先检查此账号是否已被封禁 + StpUtil.checkDisable(userId); + // 2、检查通过后,再登录 + StpUtil.login(userId); + return SaResult.ok("账号登录成功"); + } + + // 会话注销接口 ---- http://localhost:8081/disable/logout + @RequestMapping("logout") + public SaResult logout() { + StpUtil.logout(); + return SaResult.ok("账号退出成功"); + } + + // 封禁指定账号 ---- http://localhost:8081/disable/disable + @RequestMapping("disable") + public SaResult disable(long userId) { + /* + * 账号封禁: + * 参数1:要封禁的账号id + * 参数2:要封禁的时间,单位:秒,86400秒=1天 + */ + StpUtil.disable(userId, 86400); + return SaResult.ok("账号 " + userId + " 封禁成功"); + } + +} diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/HttpBasicController.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/HttpBasicController.java new file mode 100644 index 00000000..8d328576 --- /dev/null +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/HttpBasicController.java @@ -0,0 +1,38 @@ +package com.pj.cases.up; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import cn.dev33.satoken.basic.SaBasicUtil; +import cn.dev33.satoken.util.SaResult; + +/** + * Sa-Token Http Basic 认证 + * + * @author kong + * @since 2022-10-17 + */ +@RestController +@RequestMapping("/basic/") +public class HttpBasicController { + + /* + * 测试步骤: + 1、访问资源接口,被拦截,无法返回数据信息 ---- http://localhost:8081/basic/getInfo + 2、浏览器弹出窗口,要求输入账号密码,输入:账号=sa,密码=123456,确认 + 3、后端返回数据信息 + 4、后续再次访问接口时,无需重复输入账号密码 + */ + + // 资源接口 ---- http://localhost:8081/basic/getInfo + @RequestMapping("getInfo") + public SaResult login() { + // 1、Http Basic 认证校验,账号=sa,密码=123456 + SaBasicUtil.check("sa:123456"); + + // 2、返回数据 + String data = "这是通过 Http Basic 校验后才返回的数据"; + return SaResult.data(data); + } + +} diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/MutexLoginController.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/MutexLoginController.java new file mode 100644 index 00000000..688393c0 --- /dev/null +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/MutexLoginController.java @@ -0,0 +1,68 @@ +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-17 + */ +@RestController +@RequestMapping("/mutex/") +public class MutexLoginController { + + /* + * 前提1:准备至少四个浏览器:A、B、C、D + * 前提2:配置文件需要把 sa-token.is-concurrent 的值改为 false + * + * 测试步骤: + 1、在浏览器A上登录账号10001,设备为PC ---- http://localhost:8081/mutex/login?userId=10001&device=PC + 检查是否登录成功,返回true: ---- http://localhost:8081/mutex/isLogin + + 2、在浏览器B上登录账号10001,设备为APP ---- http://localhost:8081/mutex/login?userId=10001&device=APP + 检查是否登录成功,返回true: ---- http://localhost:8081/mutex/isLogin + + 3、复查一下览器A上的账号是否登录,发现并没有顶替下去,原因是两个浏览器指定的登录设备不同,允许同时在线 + ---- http://localhost:8081/mutex/isLogin + + 4、在浏览器C上登录账号10001,设备为PC ---- http://localhost:8081/mutex/login?userId=10001&device=PC + 检查是否登录成功,返回true: ---- http://localhost:8081/mutex/isLogin + + 5、复查一下浏览器A上的账号是否登录,发现账号已被顶替下线 + ---- http://localhost:8081/mutex/isLogin + + 6、再复查一下浏览器B上的账号是否登录,发现账号未被顶替下线,因为浏览器B上登录的设备是APP,而浏览器C顶替的设备是PC + ---- http://localhost:8081/mutex/isLogin + + 7、此时再从浏览器D上登录账号10001,设备为APP ---- http://localhost:8081/mutex/login?userId=10001&device=APP + 检查是否登录成功,返回true: ---- http://localhost:8081/mutex/isLogin + + 8、此时再复查一下浏览器B上的账号是否登录,发现账号已被顶替下线 + ---- http://localhost:8081/mutex/isLogin + */ + + // 会话登录接口 ---- http://localhost:8081/mutex/doLogin?userId=10001&device=PC + @RequestMapping("login") + public SaResult login(long userId, String device) { + /* + * 参数1:要登录的账号 + * 参数2:此账号在什么设备上登录的 + */ + StpUtil.login(userId, device); + return SaResult.ok("登录成功"); + } + + // 查询当前登录状态 ---- http://localhost:8081/mutex/isLogin + @RequestMapping("isLogin") + public SaResult isLogin() { + // StpUtil.isLogin() 查询当前客户端是否登录,返回 true 或 false + boolean isLogin = StpUtil.isLogin(); + return SaResult.ok("当前客户端是否登录:" + isLogin + ",登录的设备是:" + StpUtil.getLoginDevice()); + } + +} diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/SearchSessionController.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/SearchSessionController.java new file mode 100644 index 00000000..e32e6cfa --- /dev/null +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/cases/up/SearchSessionController.java @@ -0,0 +1,80 @@ +package com.pj.cases.up; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +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.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; + +/** + * Sa-Token 会话查询示例 + * + * @author kong + * @since 2022-10-17 + */ +@RestController +@RequestMapping("/search/") +public class SearchSessionController { + + /* + * 测试步骤: + 1、先登录5个账号 + ---- http://localhost:8081/search/login?userId=10001&张三&age=18 + ---- http://localhost:8081/search/login?userId=10002&李四&age=20 + ---- http://localhost:8081/search/login?userId=10003&王五&age=22 + ---- http://localhost:8081/search/login?userId=10004&赵六&age=24 + ---- http://localhost:8081/search/login?userId=10005&冯七&age=26 + + 2、根据分页参数获取会话列表 + http://localhost:8081/search/getList?start=0&size=10 + */ + + // 会话登录接口 ---- http://localhost:8081/search/login?userId=10001&张三&age=18 + @RequestMapping("login") + public SaResult login(long userId, String name, int age) { + // 先登录上 + StpUtil.login(userId); + + // 再把 User 对象存储在 SaSession 上 + SysUser user = new SysUser(); + user.setId(userId); + user.setName(name); + user.setAge(age); + StpUtil.getSession().set("user", user); + + // 返回 + return SaResult.ok("账号登录成功"); + } + + // 会话查询接口 ---- http://localhost:8081/search/getList?start=0&size=10 + @RequestMapping("getList") + public SaResult getList(int start, int size) { + // 创建集合 + List sessionList = new ArrayList<>(); + + // 分页查询数据 + List sessionIdList = StpUtil.searchSessionId("", start, size, false); + for (String sessionId: sessionIdList) { + SaSession session = StpUtil.getSessionBySessionId(sessionId); + sessionList.add(session); + } + + // 返回 + return SaResult.data(sessionList); + } + + // 会话查询接口 ---- http://localhost:8081/disable/logout + @RequestMapping("logout") + public SaResult logout() { + StpUtil.logout(); + return SaResult.ok("账号退出成功"); + } + +} diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/current/GlobalException.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/current/GlobalException.java index 787a4a32..5ab4b887 100644 --- a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/current/GlobalException.java +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/current/GlobalException.java @@ -3,6 +3,8 @@ package com.pj.current; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import cn.dev33.satoken.exception.DisableServiceException; +import cn.dev33.satoken.exception.NotBasicAuthException; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotRoleException; @@ -47,6 +49,20 @@ public class GlobalException { return SaResult.error("二级认证校验失败"); } + // 拦截:服务封禁异常 + @ExceptionHandler(DisableServiceException.class) + public SaResult handlerException(DisableServiceException e) { + e.printStackTrace(); + return SaResult.error("当前账号 " + e.getService() + " 服务已被封禁 (level=" + e.getLevel() + "):" + e.getDisableTime() + "秒后解封"); + } + + // 拦截:Http Basic 校验失败异常 + @ExceptionHandler(NotBasicAuthException.class) + public SaResult handlerException(NotBasicAuthException e) { + e.printStackTrace(); + return SaResult.error(e.getMessage()); + } + // 拦截:其它所有异常 @ExceptionHandler(Exception.class) public SaResult handlerException(Exception e) { diff --git a/sa-token-doc/_sidebar.md b/sa-token-doc/_sidebar.md index 31e5260e..70f7401c 100644 --- a/sa-token-doc/_sidebar.md +++ b/sa-token-doc/_sidebar.md @@ -26,7 +26,7 @@ - [同端互斥登录](/up/mutex-login) - [账号封禁](/up/disable) - [密码加密](/up/password-secure) - - [会话治理](/up/search-session) + - [会话查询](/up/search-session) - [Http Basic 认证](/up/basic-auth) - [全局侦听器](/up/global-listener) - [全局过滤器](/up/global-filter) diff --git a/sa-token-doc/up/basic-auth.md b/sa-token-doc/up/basic-auth.md index 3a2225fd..ea0aec43 100644 --- a/sa-token-doc/up/basic-auth.md +++ b/sa-token-doc/up/basic-auth.md @@ -75,6 +75,12 @@ http://sa:123456@127.0.0.1:8081/test/test3 ``` +--- + + + 本章代码示例:Sa-Token 账号禁用 —— [ com.pj.cases.up.DisableController.java ] + diff --git a/sa-token-doc/up/disable.md b/sa-token-doc/up/disable.md index 256dc181..8a6aac1f 100644 --- a/sa-token-doc/up/disable.md +++ b/sa-token-doc/up/disable.md @@ -230,3 +230,10 @@ public SaResult send() { ``` + +--- + + + 本章代码示例:Sa-Token 账号禁用 —— [ com.pj.cases.up.DisableController.java ] + \ No newline at end of file diff --git a/sa-token-doc/up/mutex-login.md b/sa-token-doc/up/mutex-login.md index 66721f8c..9905b315 100644 --- a/sa-token-doc/up/mutex-login.md +++ b/sa-token-doc/up/mutex-login.md @@ -43,3 +43,10 @@ StpUtil.getLoginDevice(); StpUtil.getTokenValueByLoginId(10001, "APP"); ``` + +--- + + + 本章代码示例:Sa-Token 同端互斥登录 —— [ com.pj.cases.up.MutexLoginController.java ] + \ No newline at end of file diff --git a/sa-token-doc/up/search-session.md b/sa-token-doc/up/search-session.md index 0f74aa68..fb52232e 100644 --- a/sa-token-doc/up/search-session.md +++ b/sa-token-doc/up/search-session.md @@ -1,4 +1,4 @@ -# 会话治理 +# 会话查询 尽管框架将大部分操作提供了简易的封装,但在一些特殊场景下,我们仍需要绕过框架,直达数据底层进行一些操作。 @@ -83,4 +83,14 @@ for (String sessionId : sessionIdList) { 请根据业务实际水平合理调用API。 -> 如果需要实时获取当前登录人数或者需要在用户退出后自动触发某事件等, 建议采用websocket技术。 \ No newline at end of file +> 如果需要实时获取当前登录人数或者需要在用户退出后自动触发某事件等,建议采用 WebSocket。 + + +--- + + + 本章代码示例:Sa-Token 会话查询 —— [ com.pj.cases.up.SearchSessionController.java ] + + +