From 2fbafcdd3e395b56d330d1fdb2bcfcf23ba1bd62 Mon Sep 17 00:00:00 2001
From: click33 <36243476+click33@users.noreply.github.com>
Date: Tue, 1 Apr 2025 05:33:10 +0800
Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9EQA=EF=BC=9A=E8=A7=A3?=
=?UTF-8?q?=E5=86=B3=E4=BD=8E=E7=89=88=E6=9C=AC=20SpringBoot=20(<2.2.0)=20?=
=?UTF-8?q?=E5=BC=95=E5=85=A5=20Sa-Token=20=E6=8A=A5=E9=94=99=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sa-token-demo/pom.xml | 1 +
.../pom.xml | 146 ++++++++++++++++++
.../main/java/com/pj/SaTokenApplication.java | 22 +++
.../java/com/pj/current/GlobalException.java | 28 ++++
.../java/com/pj/satoken/SaTokenConfigure.java | 87 +++++++++++
.../java/com/pj/test/LoginController.java | 71 +++++++++
.../src/main/resources/application.yml | 49 ++++++
sa-token-doc/more/common-questions.md | 25 +++
8 files changed, 429 insertions(+)
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/pom.xml
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/SaTokenApplication.java
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/current/GlobalException.java
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/satoken/SaTokenConfigure.java
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/test/LoginController.java
create mode 100644 sa-token-demo/sa-token-demo-springboot-low-version/src/main/resources/application.yml
diff --git a/sa-token-demo/pom.xml b/sa-token-demo/pom.xml
index 26ebcbd4..a9bed331 100644
--- a/sa-token-demo/pom.xml
+++ b/sa-token-demo/pom.xml
@@ -33,6 +33,7 @@
sa-token-demo-solon-redisson
sa-token-demo-springboot
sa-token-demo-springboot3-redis
+ sa-token-demo-springboot-low-version
sa-token-demo-springboot-redis
sa-token-demo-springboot-redisson
sa-token-demo-ssm
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/pom.xml b/sa-token-demo/sa-token-demo-springboot-low-version/pom.xml
new file mode 100644
index 00000000..03358c11
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/pom.xml
@@ -0,0 +1,146 @@
+
+ 4.0.0
+ cn.dev33
+ sa-token-demo-springboot-low-version
+ 0.0.1-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+
+
+
+ 2.1.18.RELEASE
+
+
+
+
+
+ 1.41.0
+ com.pj.SaTokenApplication
+ 1.8
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ cn.dev33
+ sa-token-spring-boot-starter
+ ${sa-token.version}
+
+
+
+ cn.hutool
+ hutool-all
+ 5.8.36
+
+
+
+
+ cn.dev33
+ sa-token-redis-template
+ ${sa-token.version}
+
+
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.17.3
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.17.3
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.17.3
+
+
+
+
+
+
+
+
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+ src/main/resources
+
+ **/*.*
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ true
+ lib/
+ ${java.run.main.class}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy
+ package
+
+ copy-dependencies
+
+
+
+ ${project.build.directory}/lib
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/SaTokenApplication.java b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/SaTokenApplication.java
new file mode 100644
index 00000000..a6ddba2e
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/SaTokenApplication.java
@@ -0,0 +1,22 @@
+package com.pj;
+
+import cn.dev33.satoken.SaManager;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+
+/**
+ * Sa-Token 测试
+ * @author click33
+ *
+ */
+@SpringBootApplication
+public class SaTokenApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SaTokenApplication.class, args);
+ System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
+// System.out.println(StpUtil.getSessionByLoginId(10001));
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/current/GlobalException.java b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/current/GlobalException.java
new file mode 100644
index 00000000..649bdf06
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/current/GlobalException.java
@@ -0,0 +1,28 @@
+package com.pj.current;
+
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 全局异常处理
+ */
+@RestControllerAdvice
+public class GlobalException {
+
+ // 全局异常拦截(拦截项目中的所有异常)
+ @ExceptionHandler
+ public SaResult handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) {
+
+ // 打印堆栈,以供调试
+ System.out.println("全局异常---------------");
+ e.printStackTrace();
+
+ // 返回给前端
+ return SaResult.error(e.getMessage());
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/satoken/SaTokenConfigure.java
new file mode 100644
index 00000000..2ad7f768
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/satoken/SaTokenConfigure.java
@@ -0,0 +1,87 @@
+package com.pj.satoken;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.interceptor.SaInterceptor;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+
+/**
+ * [Sa-Token 权限认证] 配置类
+ * @author click33
+ *
+ */
+@Configuration
+public class SaTokenConfigure implements WebMvcConfigurer {
+
+ /**
+ * 注册 Sa-Token 拦截器打开注解鉴权功能
+ */
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ // 注册 Sa-Token 拦截器打开注解鉴权功能
+ registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
+ }
+
+ /**
+ * 注册 [Sa-Token 全局过滤器]
+ */
+ @Bean
+ public SaServletFilter getSaServletFilter() {
+ return new SaServletFilter()
+
+ // 指定 [拦截路由] 与 [放行路由]
+ .addInclude("/**")// .addExclude("/favicon.ico")
+
+ // 认证函数: 每次请求执行
+ .setAuth(obj -> {
+ // 输出 API 请求日志,方便调试代码
+ // SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
+
+ })
+
+ // 异常处理函数:每次认证函数发生异常时执行此函数
+ .setError(e -> {
+ System.out.println("---------- sa全局异常 ");
+ e.printStackTrace();
+ return SaResult.error(e.getMessage());
+ })
+
+ // 前置函数:在每次认证函数之前执行
+ .setBeforeAuth(obj -> {
+ // ---------- 设置一些安全响应头 ----------
+ SaHolder.getResponse()
+ // 服务器名称
+ .setServer("sa-server")
+ // 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
+ .setHeader("X-Frame-Options", "SAMEORIGIN")
+ // 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面
+ .setHeader("X-XSS-Protection", "1; mode=block")
+ // 禁用浏览器内容嗅探
+ .setHeader("X-Content-Type-Options", "nosniff")
+
+ // ---------- 设置跨域响应头 ----------
+ // 允许指定域访问跨域资源
+ .setHeader("Access-Control-Allow-Origin", "*")
+ // 允许所有请求方式
+ .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+ // 有效时间
+ .setHeader("Access-Control-Max-Age", "3600")
+ // 允许的header参数
+ .setHeader("Access-Control-Allow-Headers", "*");
+
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+ .back();
+ })
+ ;
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/test/LoginController.java b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/test/LoginController.java
new file mode 100644
index 00000000..bf7650ec
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/java/com/pj/test/LoginController.java
@@ -0,0 +1,71 @@
+package com.pj.test;
+
+import cn.dev33.satoken.session.SaTerminalInfo;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.stp.parameter.SaLoginParameter;
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 登录测试
+ * @author click33
+ *
+ */
+@RestController
+@RequestMapping("/acc/")
+public class LoginController {
+
+ // 测试登录 ---- 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)) {
+ StpUtil.login(10001);
+ StpUtil.getTokenSession();
+ return SaResult.ok("登录成功");
+ }
+ return SaResult.error("登录失败");
+ }
+
+ // 查询登录状态 ---- http://localhost:8081/acc/isLogin
+ @RequestMapping("isLogin")
+ public SaResult isLogin() {
+ return SaResult.ok("是否登录:" + StpUtil.isLogin());
+ }
+
+ // 校验登录 ---- http://localhost:8081/acc/checkLogin
+ @RequestMapping("checkLogin")
+ public SaResult checkLogin() {
+ StpUtil.checkLogin();
+ return SaResult.ok();
+ }
+
+ // 查询 Token 信息 ---- http://localhost:8081/acc/tokenInfo
+ @RequestMapping("tokenInfo")
+ public SaResult tokenInfo() {
+ return SaResult.data(StpUtil.getTokenInfo());
+ }
+
+ // 查询账号登录设备信息 ---- http://localhost:8081/acc/terminalInfo
+ @RequestMapping("terminalInfo")
+ public SaResult terminalInfo() {
+ System.out.println("账号 10001 登录设备信息:");
+ List terminalList = StpUtil.getTerminalListByLoginId(10001);
+ for (SaTerminalInfo ter : terminalList) {
+ System.out.println("登录index=" + ter.getIndex() + ", 设备type=" + ter.getDeviceType() + ", token=" + ter.getTokenValue() + ", 登录time=" + ter.getCreateTime());
+ }
+ return SaResult.data(terminalList);
+ }
+
+
+ // 测试注销 ---- http://localhost:8081/acc/logout
+ @RequestMapping("logout")
+ public SaResult logout() {
+ StpUtil.login(10001, SaLoginParameter.create().setIsConcurrent(false));
+ return SaResult.ok();
+ }
+
+}
diff --git a/sa-token-demo/sa-token-demo-springboot-low-version/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/resources/application.yml
new file mode 100644
index 00000000..ac474574
--- /dev/null
+++ b/sa-token-demo/sa-token-demo-springboot-low-version/src/main/resources/application.yml
@@ -0,0 +1,49 @@
+# 端口
+server:
+ port: 8081
+
+############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
+sa-token:
+ # token 名称 (同时也是 cookie 名称)
+ token-name: satoken
+ # token 有效期(单位:秒) 默认30天,-1 代表永久有效
+ timeout: 2592000
+ # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
+ active-timeout: -1
+ # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
+ is-concurrent: true
+ # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
+ is-share: false
+ # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
+ token-style: uuid
+ # 是否输出操作日志
+ is-log: true
+
+spring:
+ # redis配置
+ redis:
+ # Redis数据库索引(默认为0)
+ database: 0
+ # Redis服务器地址
+ host: 127.0.0.1
+ # Redis服务器连接端口
+ port: 6379
+ # Redis服务器连接密码(默认为空)
+ password:
+ # 连接超时时间
+ timeout: 10s
+ lettuce:
+ pool:
+ # 连接池最大连接数
+ max-active: 200
+ # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: -1ms
+ # 连接池中的最大空闲连接
+ max-idle: 10
+ # 连接池中的最小空闲连接
+ min-idle: 0
+
+
+
+
+
\ No newline at end of file
diff --git a/sa-token-doc/more/common-questions.md b/sa-token-doc/more/common-questions.md
index 45c3c4de..050bcb86 100644
--- a/sa-token-doc/more/common-questions.md
+++ b/sa-token-doc/more/common-questions.md
@@ -565,9 +565,34 @@ public class SaTokenContextByPatternsRequestCondition extends SaTokenContextForS
```
+### Q:过低的 SpringBoot 版本引入 Sa-Token 后报错
+在低于 2.2.0 时 (不包含2.2.0本身) 的 SpringBoot 项目中引入 Sa-Token 后,项目启动时会报错:
+``` txt
+org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.dev33.satoken.spring.SaBeanInject': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.dev33.satoken.spring.SaBeanInject]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/jsontype/PolymorphicTypeValidator
+```
+这是由于缺少 jackson 相关依赖导致的,可以手动添加以下依赖来解决:
+
+``` xml
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.17.3
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.17.3
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.17.3
+
+```