diff --git a/sa-token-doc/README.md b/sa-token-doc/README.md index 0263fa21..fa42c77d 100644 --- a/sa-token-doc/README.md +++ b/sa-token-doc/README.md @@ -100,7 +100,7 @@ Sa-Token 目前主要五大功能模块:登录认证、权限认证、单点 - **临时Token认证** —— 解决短时间的Token授权问题 - **模拟他人账号** —— 实时操作任意用户状态数据 - **临时身份切换** —— 将会话身份临时切换为其它账号 -- **前后台分离** —— APP、小程序等不支持Cookie的终端 +- **前后端分离** —— APP、小程序等不支持Cookie的终端 - **同端互斥登录** —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录 - **多账号认证体系** —— 比如一个商城项目的user表和admin表分开鉴权 - **Token风格定制** —— 内置六种Token风格,还可:自定义Token生成策略、自定义Token前缀 diff --git a/sa-token-doc/_sidebar.md b/sa-token-doc/_sidebar.md index abe44404..569a2496 100644 --- a/sa-token-doc/_sidebar.md +++ b/sa-token-doc/_sidebar.md @@ -16,10 +16,10 @@ - [框架配置](/use/config) - **深入** - - [集成Redis](/up/integ-redis) - - [前后台分离](/up/not-cookie) - - [自定义Token风格](/up/token-style) - - [自定义Token前缀](/up/token-prefix) + - [集成 Redis](/up/integ-redis) + - [前后端分离](/up/not-cookie) + - [自定义 Token 风格](/up/token-style) + - [自定义 Token 前缀](/up/token-prefix) - [记住我模式](/up/remember-me) - [二级认证](/up/safe-auth) - [模拟他人 & 身份切换](/up/mock-person) diff --git a/sa-token-doc/doc.html b/sa-token-doc/doc.html index 2d324148..ac6d0ddf 100644 --- a/sa-token-doc/doc.html +++ b/sa-token-doc/doc.html @@ -4,7 +4,7 @@ Sa-Token - + diff --git a/sa-token-doc/doc/index-backup.html b/sa-token-doc/doc/index-backup.html index 96b16199..da1753c5 100644 --- a/sa-token-doc/doc/index-backup.html +++ b/sa-token-doc/doc/index-backup.html @@ -4,7 +4,7 @@ Sa-Token - + diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index 96b16199..da1753c5 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -4,7 +4,7 @@ Sa-Token - + diff --git a/sa-token-doc/index.html b/sa-token-doc/index.html index 67a11916..e2cc9031 100644 --- a/sa-token-doc/index.html +++ b/sa-token-doc/index.html @@ -4,7 +4,7 @@ Sa-Token - + diff --git a/sa-token-doc/more/blog.md b/sa-token-doc/more/blog.md index 499b09b4..47f2cd92 100644 --- a/sa-token-doc/more/blog.md +++ b/sa-token-doc/more/blog.md @@ -71,7 +71,7 @@ - [[ 掘金 ] 权限认证就它了Sa-Token](https://juejin.cn/post/6938747514837434376) (2021-3-12) -- [[ 掘金 ] sa-token之前后台分离模式下如何完成权限认证](https://juejin.cn/post/6937219472507797535) (2021-03-8) +- [[ 掘金 ] sa-token之前后端分离模式下如何完成权限认证](https://juejin.cn/post/6937219472507797535) (2021-03-8) - [[ 掘金 ] 一个登录功能也能玩出这么多花样?sa-token带你轻松搞定多地登录、单地登录、同端互斥登录](https://juejin.cn/post/6917884159491276808) (2021-1-15) diff --git a/sa-token-doc/more/common-questions.md b/sa-token-doc/more/common-questions.md index f24c3f3d..635e4e48 100644 --- a/sa-token-doc/more/common-questions.md +++ b/sa-token-doc/more/common-questions.md @@ -9,36 +9,60 @@ ## 一、常见报错 -### Q:报错:非Web上下文无法获取Request? -报错原因:Sa-Token 的部分 API 只能在 Web 上下文中调用,报这个错说明你调用 Sa-Token 的地方不在 Web 上下文中,请排查: +### Q:报错:非Web上下文无法获取Request。 -1. 是否在 main 方法中调用了 Sa-Token 的API -2. 是否在带有 `@Async` 注解的方法中调用了 Sa-Token 的API -3. 是否在一些丢失web上下文的子线程中调用了 Sa-Token 的API,例如 `MyBatis-Plus` 的 `insertFill` 自动填充 -4. 是否在一些非 Http 协议的 RPC 框架中(例如 Dubbo)调用了 Sa-Token 的API -5. 是否在 SpringBoot 启动初始化的方法中调用了 Sa-Token 的API,例如`@PostConstruct` +报错原因解析: -解决方案:先获取你想要的值,再把这个值当做一个参数传递到这些方法中,而不是直接从方法内调用 Sa-Token 的API。 +Sa-Token 的部分 API 只能在 Web 上下文中才能调用,例如:`StpUtil.getLoginId()` 获取当前用户Id,这个方法第一步需要先从前端提交的参数里获取 token 值, +当你在 main 方法里调用这个 API 时,由于 main 方法本质上不是一个 Controller 请求,所以框架无法完成 *“从前端提交的参数里获取 token 值”* 这一步骤,框架就只能抛出异常。 + +按照此标准,Sa-Token 的 API 可粗浅的分为两大类: +- 必须在 Web 上下文中才能调用的 API,例如:`StpUtil.getLoginId()`、`StpUtil.getTokenValue()` 等等。 +- 无需 Web 上下文也能调用的 API,例如:`StpUtil.getLoginType()`、`SaManager.getConfig()` 等等。 + +此处无法逐一列出到底哪些 API 属于 *“必须依赖 Web 上下文的 API”*,因为太多了,你只需要记住关键的一点: +**当一个 API 执行的代码需要先从前端请求中获取一些数据时,这个 API 就属于 *“必须依赖 Web 上下文的 API”*。** + +如果你的代码报这个错,说明你在不是 Web 上下文中的地方,调用了 *“必须依赖 Web 上下文的 API”*,请排查: + +1. 是否在 main 方法中调用了 *“必须依赖 Web 上下文的 API”*。 +2. 是否在带有 `@Async` 注解的方法中调用了 *“必须依赖 Web 上下文的 API”*。 +3. 是否在一些丢失 web 上下文的子线程中调用了 *“必须依赖 Web 上下文的 API”*,例如 `MyBatis-Plus` 的 `insertFill` 自动填充。 +4. 是否在一些非 Http 协议的 RPC 框架中(例如 Dubbo)调用了 *“必须依赖 Web 上下文的 API”*。 +5. 是否在 SpringBoot 启动初始化的方法中调用了 *“必须依赖 Web 上下文的 API”*,例如 `@PostConstruct` 修饰的方法。 +6. 是否在定时任务中调用了 *“必须依赖 Web 上下文的 API”*。 -### Q:报错:未初始化任何有效上下文处理器? -报错原因:Sa-Token底层不能确认最终运行的web容器,所以抽象了 `SaTokenContext` 接口,对接不同容器时需要注入不同的实现,通常这个注入工作都是框架自动完成的, -你只需要按照文档开始部分集成相应的依赖即可 +### Q:报错:未能获取有效的上下文处理器。 -如果报了这个错误,说明框架没有注入正确的上下文实现,请排查: +报错原因解析: + +在 sa-token-core 核心包中,Sa-Token 底层不能确认最终运行的 web 容器,所以抽象了 `SaTokenContext` 接口,对接不同容器时需要注入不同的实现, +通常这个注入工作都是框架自动完成的,你只需要按照文档开始部分集成相应的依赖即可。例如: + +- 你要在 Springboot2.x 中使用 Sa-Token,就引入:`sa-token-spring-boot-starter`。 +- 你要在 Springboot3.x 中使用 Sa-Token,就引入:`sa-token-spring-boot3-starter`。 +- 你要在基于 webflux 架构的网关中使用 Sa-Token,就引入:`sa-token-reactor-spring-boot-starter`。 +- 你要在 Solon 中使用 Sa-Token,就引入:`sa-token-solon-plugin`。 +- 等等等等…… + +如果你的代码报 *“未能获取有效的上下文处理器”* 这个错,大概率是因为你没有正确引入所需的包,导致框架没有注入正确的 `SaTokenContext` 上下文实现,请排查: 1. 如果你的项目是微服务项目,请直接参考:[微服务-依赖引入说明](/micro/import-intro),如果是单体项目,请往下看: -2. 请判断你的项目是 SpringMVC 环境还是 WebFlux 环境 +2. 请判断你的项目是 SpringMVC 环境还是 WebFlux 环境: - 如果是 SpringMVC 环境就引入 `sa-token-spring-boot-starter` 依赖,参考:[在SpringBoot环境集成](/start/example) - 如果是 WebFlux 环境就引入 `sa-token-reactor-spring-boot-starter` 依赖,参考:[在WebFlux环境集成](/start/webflux-example) - - 引入错误的依赖会导致`SaTokenContext`初始化失败,抛出上述异常 - - 如果你还无法分辨你是哪个环境,就看你的 pom.xml 依赖,如果引入了`spring-boot-starter-web`就是SpringMVC环境,如果引入了 `spring-boot-starter-webflux` 就是WebFlux环境。……什么?你说你两个都引入了?那你的项目能启动成功吗? -3. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,**请检查是否注册了全局过滤器,在 WebFlux 下这一步是必须的**。 -4. 如果以上步骤排除无误后依然报错,请直接提 issue 或者加入QQ群求助。 +3. 如果你还无法分辨你是哪个环境,就看你的 pom.xml 依赖: + - 如果引入了`spring-boot-starter-web`就是 SpringMVC 环境。 + - 如果引入了 `spring-boot-starter-webflux` 就是WebFlux环境。 + - 什么?你说你两个都引入了?那你的项目能启动成功吗? +4. 如果是 WebFlux 环境而且正确引入了依赖,依然报错,**请检查是否注册了 SaReactorFilter 全局过滤器,在 WebFlux 下这一步是必须的**,具体还是请参考上面的 [ 在WebFlux环境集成 ] 章节。 +5. 需要仔细注意,如果你使用的是 Springboot3.x 版本,就不要错误的引入 `sa-token-spring-boot-starter`,需要引入的是 `sa-token-spring-boot3-starter`,不然就会导致框架报错。 +6. 如果以上步骤排除无误后依然报错,请直接提 issue 或者加入QQ群求助。 ### Q:报错:NotLoginException:xxx -这个错是说明调用接口的人没有通过登录校验,请注意通常**异常提示语已经描述清楚了没有通过认证的具体原因:** +这个错是说明调用接口的人没有通过登录校验,请注意:**通常情况下,异常提示语已经描述清楚了没有通过校验的具体原因:** **如果是:未能读取到有效Token** - 可能1:前端没有提交 Token(最好从前端f12控制台看看请求参数里有 token 吗)。 @@ -216,7 +240,7 @@ sa-token: ### Q:我自定义了组件,但是好像没有生效? -1、情况1是可能组件没有注入成功,排查方法为在 main 里打印这个组件,是否为自定义的class限定名: +1、可能组件没有注入成功,排查方法为在 main 里打印这个组件,是否为自定义的class限定名: ``` java @SpringBootApplication public class SaTokenApplication { @@ -231,7 +255,7 @@ public class SaTokenApplication { - 自定义的组件实现类是否在启动类的同目录或者子目录上,如果不在则无法被 springboot 启动时扫描,扫描不到也就无法注入。 - 启动类上是否加了 `@ComponentScan` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。 -2、情况2是,这个组件注入成功了,但是还没到执行时机,比如 `StpInterface` 组件,只有在鉴权时才会触发,如果你的代码仅仅是登录校验,就不会执行到这个组件。 +2、这个组件注入成功了,但是还没到执行时机,比如 `StpInterface` 组件,只有在鉴权时才会触发,如果你的代码仅仅是登录校验,就不会执行到这个组件。 ### Q:集成 Redis 后,明明 Redis 中有值,却还是提示无效Token? @@ -337,7 +361,9 @@ public class User implements Serializable { private String username; private String password; } +``` +``` java User user = new User(); user.setUserId(10000L); user.setUsername("oneName"); @@ -350,9 +376,9 @@ SerializationException: Could not read JSON: Cannot deserialize value of type `java.lang.Long` from Array value (token `JsonToken.START_ARRAY`) ``` -springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能出现此问题 +Springboot 集成 Sa-Token Redis 后, 一旦 Springboot 切换版本就有可能出现此问题 -原因是redis里面有之前的 satoken 会话数据, 清空 Redis 即可 +原因是 Redis 里面有之前的 Sa-Token 会话数据, 清空 Redis 即可。 @@ -397,10 +423,35 @@ Caused by: java.lang.ClassNotFoundException: cn.dev33.satoken.same.SaSameTemplat ### Q:登录方法需要我自己实现吗? 是的,不同于`shiro`等框架,`Sa-Token`不会在登录流程中强插一脚,开发者比对完用户的账号和密码之后,只需要调用`StpUtil.login(id)`通知一下框架即可 +``` java +// 会话登录接口 +@RequestMapping("doLogin") +public SaResult doLogin(String name, String pwd) { + // 第一步:比对前端提交的账号名称、密码 + if("zhang".equals(name) && "123456".equals(pwd)) { + + // 第二步:比对成功后,调用通知框架,xxx账号登录成功 + StpUtil.login(10001); + return SaResult.ok("登录成功"); + } + return SaResult.error("登录失败"); +} +``` ### Q:框架抛出的权限不足异常,我想根据自定义提示信息,可以吗? 可以,在全局异常拦截器里捕获`NotPermissionException`,可以通过`getPermission()`获取没有通过认证的权限码,可以据此自定义返回信息 +``` java +@RestControllerAdvice +public class GlobalExceptionHandler { + // 全局 NotPermissionException 异常捕获 + @ExceptionHandler(NotPermissionException.class) + public SaResult handlerException(NotPermissionException e) { + e.printStackTrace(); + return SaResult.error("缺少权限:" + e.getPermission()); + } +} +``` ### Q:我的项目权限模型不是RBAC模型,很复杂,可以集成吗? 无论什么模型,只要能把一个用户具有的所有权限塞到一个List里返回给框架,就能集成 @@ -439,11 +490,11 @@ SaRouter.match("/**").notMatch("/login", "/reg").check(r -> StpUtil.checkLogin() `StpUtil.login()`只是为了给当前会话做个唯一标记,通常写入`UserId`即可,如果要存储User对象,可以使用`StpUtil.getSession()`获取Session对象进行存储。 -### Q:前后台分离模式下和普通模式有何不同? -主要是失去了`Cookie`无法自动化保存和提交`token秘钥`,可以参考章节:[前后台分离](/up/not-cookie) +### Q:前后端分离模式下和普通模式有何不同? +主要是失去了`Cookie`无法自动化保存和提交`token秘钥`,可以参考章节:[前后端分离](/up/not-cookie) -### Q:前后台分离时,前端提交的 header 参数是叫 token 还是 satoken 还是 tokenName? +### Q:前后端分离时,前端提交的 header 参数是叫 token 还是 satoken 还是 tokenName? 默认是satoken,如果想换一个名字,更改一下配置文件的`tokenName`即可。 @@ -489,6 +540,11 @@ So:从鉴权粒度的角度来看,需要针对一个模块鉴权的时候, 为了保证相关组件能够及时初始化,框架默认给过滤器注册的优先级为-100,如果你想更改优先级,直接在注册过滤器的方法上加上 `@Order(xxx)` 即可覆盖框架的默认配置 -### Q:还是有不明白到的地方? -请在`gitee` 、 `github` 提交 `issues`,或者加入qq群交流(群链接在[首页](README?id=交流群)) +### timeout 过期了,获取到的 NotLoginException 场景值是-2,按照文档说的应该是-3吧。是我理解的不对还是操作有误? +你的理解是对的,但是框架现在只能做到返回-2,因为 token 过期后,就从 Redis 中消失了,框架没法分辨这个 token 是曾经有过然后过期的,还是从来就没有在Redis中存在过, +所以只能统一抛出-2,这个行为也和具体使用的 SaTokenDao 有关联,例如集成 sa-token-jwt 插件后,框架就能分辨出来是 token 过期了,抛出-3。 + + +### Q:还是有不明白到的地方? +请在`gitee` 、 `github` 提交 `issues`,或者加入qq群交流,[群链接](/more/join-group) diff --git a/sa-token-doc/sso/readme.md b/sa-token-doc/sso/readme.md index c09f4354..1f2eb104 100644 --- a/sa-token-doc/sso/readme.md +++ b/sa-token-doc/sso/readme.md @@ -38,4 +38,10 @@ Sa-Token-SSO 由简入难划分为三种模式,解决不同架构下的 SSO 6. 高可定制:Sa-Token-SSO模块对代码架构侵入性极低,结合Sa-Token本身的路由拦截特性,你可以非常轻松的定制化开发。 +### 学习注意点 +1. sa-token-sso 虽然是个单独的插件,但其本质仍是对 Sa-Token 本身各个功能的组合使用,所以先熟练掌握 Sa-Token 可有效降低 SSO 章节的学习压力。 +2. 相比单体系统的会话管理,SSO 登录与注销的整体链路较长,出现 bug 时调试步骤也更复杂,因此建议先通过 demo 打通各个技术细节,再正式集成到项目中。 +3. 文档对 跨Redis、跨域、前后端分离 等常见场景提供直接可用的示例,但真实项目往往是多种特殊场景交叉组合存在,每个项目各不相同。 +所以文档无法依次列出所有技术点交叉组合的 demo 示例,文档会更注重解释清楚每一种特殊场景的特殊点所在,以及其解决原理, +所以推荐大家细心阅读相关段落,以便在真实项目中可以做到灵活组合、举一反三。 diff --git a/sa-token-doc/sso/sso-h5.md b/sa-token-doc/sso/sso-h5.md index 91a8e567..1a9af5aa 100644 --- a/sa-token-doc/sso/sso-h5.md +++ b/sa-token-doc/sso/sso-h5.md @@ -2,14 +2,14 @@ --- -如果我们已有的系统是前后端分离模式,我们显然不能为了接入SSO而改造系统的基础架构,官方仓库的示例采用的是前后端一体方案,要将其改造为前后台分离架构模式非常简单 +如果我们已有的系统是前后端分离模式,我们显然不能为了接入SSO而改造系统的基础架构,官方仓库的示例采用的是前后端一体方案,要将其改造为前后端分离架构模式非常简单 以`sa-token-demo-sso2-client`为例: ### 1、新建`H5Controller`开放接口 ``` java /** - * 前后台分离架构下集成SSO所需的代码 + * 前后端分离架构下集成SSO所需的代码 */ @RestController public class H5Controller { @@ -105,8 +105,8 @@ public class H5Controller { 先启动Server服务端与Client服务端,再随便找个能预览html的工具打开前端项目(比如[HBuilderX](https://www.dcloud.io/hbuilderx.html)),测试流程与一体版一致 -### 6、SSO-Server 端的前后台分离 -疑问:上述代码都是针对 Client 端进行拆分,如果我想在 SSO-Server 端也进行前后台分离改造,应该怎么做? +### 6、SSO-Server 端的前后端分离 +疑问:上述代码都是针对 Client 端进行拆分,如果我想在 SSO-Server 端也进行前后端分离改造,应该怎么做? > 答:解决思路都是大同小异的,与Client一样,我们需要把原本在 “后端处理的授权重定向逻辑” 拿到前端来实现。 diff --git a/sa-token-doc/sso/sso-questions.md b/sa-token-doc/sso/sso-questions.md index e5a87efb..1d0b8843 100644 --- a/sa-token-doc/sso/sso-questions.md +++ b/sa-token-doc/sso/sso-questions.md @@ -6,24 +6,25 @@ SSO 集成常见问题整理 --- -### 问:在模式一与模式二中,Client端 必须通过 Alone-Redis 插件来访问Redis吗? -答:不必须,只是推荐,权限缓存与业务缓存分离后会减少 `SSO-Redis` 的访问压力,且可以避免多个 `Client端` 的缓存读写冲突 +### 问:在模式一与模式二中,Client端 必须通过 Alone-Redis 插件来访问 Redis 吗? +答:不必须,只是推荐,权限缓存与业务缓存分离后会减少 `SSO-Redis` 的访问压力,且可以避免多个 `Client端` 的缓存读写冲突。 -### 问:将旧有系统改造为单点登录时,应该注意哪些? -答:建议不要把其中一个系统改造为SSO服务端,而是新起一个项目作为Server端,所有旧有项目全部作为Client端与此对接 +### 问:搭建好 sso-server 或 sso-client 服务后,访问返回:`{"msg": "not handle"}`。 +返回这个信息,代表你访问的路由有错误,比如说: -### 问:SSO模式二,第一个域名登录成功之后其他两个不会自动登录? -答:系统1登录成功之后,系统二与系统三需要点击登录按钮,才会登录成功 +- 统一认证登录地址是:`http://{host}:{port}/sso/auth`。 +- 而你访问的却是:`http://{host}:{port}/sso/auth2`。 -> 第一个系统,需要:点击 [登录] 按钮 -> 跳转到登录页 -> 输账号密码 -> 登录成功
-> 第二个系统,需要:点击 [登录] 按钮 -> 登录成功
-> 第三个系统,需要:点击 [登录] 按钮 -> 登录成功 (免去重复跳转登录页输入账号密码的步骤) +地址写错了,框架就不会处理这个请求,会直接返回 `{"msg": "not handle"}`,所有开放地址可参考:[SSO 开放接口](/sso/sso-apidoc) +如果仔细检查地址后没有写错,却依然返回了这个信息,那有可能是对应的接口没有打开,比如说: -### 追问:那我是否可以设计成不需要点登录按钮的,只要访问页面,它就能登录成功 -可以:加个过滤器检测到未登录 自动跳转就行了,详细可以参照章节:[[何时引导用户去登录]](/sso/sso-custom-login) 给出的建议进行设计 +- sso-server 端的单点注销地址:`http://{host}:{port}/sso/signout`; +- sso-client 端的注销地址:`http://{host}:{port}/sso/logout`; + +都需要在配置文件配置:`sa-token.sso.is-slo=true`后,才会打开。 ### 问:我参照文档搭建SSO-Client,一直提示:Ticket无效,请问怎么回事? @@ -34,6 +35,18 @@ SSO 集成常见问题整理 我的建议是:排查时不要仅凭肉眼判断,分别在你的 `Client` 与 `Server` 启动后调用 `SaManager.getSaTokenDao().set("name", "value", 100000);` 随便写入一个值,看看能不能根据你的预期写进同一个Redis里,如果能的话才能证明 `Client` 与 `Server` 连接的Reids 是同一个,再进行下一步排查。 +``` java +@SpringBootApplication +public class SaSsoServerApplication { + public static void main(String[] args) { + SpringApplication.run(SaSsoServerApplication.class, args); + System.out.println("\n------ Sa-Token-SSO 统一认证中心启动成功 "); + // 分别在 Client 与 Server 启动后调用 set 数据代码,看看能否根据预期写入同一个 reids + SaManager.getSaTokenDao().set("name", "value", 100000); + } +} +``` + 如果使用的是模式三,则排查是否有重复校验 ticket 的代码,一个 ticket 码只能使用一次,多次重复使用就会提示这个。 @@ -44,6 +57,60 @@ SSO 集成常见问题整理 解决方案:在 sso-client 也新建上这个类,而且包名需要与 sso-server 端的一致(直接从 sso-server 把实体类复制过来就好了) + +### 问:SSO模式二或模式三,第一个 client 登录成功之后再访问其它两个 client 不会自动登录,需要点一下登录按钮才会登录上? +答:这是正常现象,系统 1 登录成功之后,系统 2 与系统 3 需要点击登录按钮,才会登录成功。 + +> 第一个系统,需要:点击 [登录] 按钮 -> 跳转到登录页 -> 输账号密码 -> 登录成功
+> 第二个系统,需要:点击 [登录] 按钮 -> 登录成功
+> 第三个系统,需要:点击 [登录] 按钮 -> 登录成功 +> +> (系统二、三 免去重复跳转登录页输入账号密码的步骤) + + +### 追问:那我是否可以设计成不需要点登录按钮的,只要访问页面,它就能登录成功? +可以的。 + +其实思路很简单,我们只需要给 client 项目加个过滤器,拦截所有请求,只要检测到未登录就将其重定向至登录页面: + +``` java +/** + * Sa-Token 配置类 + */ +@Configuration +public class SaTokenConfigure implements WebMvcConfigurer { + /** 注册 [Sa-Token全局过滤器] */ + @Bean + public SaServletFilter getSaServletFilter() { + return new SaServletFilter() + .addInclude("/**") + .addExclude("/sso/*", "/favicon.ico") // 这里需要注意排除掉 /sso/* 相关请求不拦截,否则就会触发无限重定向 + .setAuth(obj -> { + /* + * 这里会被分为两种情况: + * 情况1:这个请求在当前 client 已经登录,此时会顺利进入网站 + * 情况2:这个请求在当前 client 尚未登录,此时会被拦截,重定向至当前系统的 /sso/login?back=当前地址 + * + * 情况2会带领着用户继续重定向至 sso-server 认证中心,此时又分为两种情况: + * 情况2.1:此用户在 sso-server 尚未登录,此时会停留在登录页面,开始输入账号密码进行登录 + * 情况2.2:此用户在 sso-server 已经登录(这证明此用户已经在其它至少一个 sso-client 处完成了登录) + * 此时用户会继续重定向回当前 client,并携带 ticket 参数,完成登录。 + */ + if(StpUtil.isLogin() == false) { + String back = SaFoxUtil.joinParam(SaHolder.getRequest().getUrl(), SpringMVCUtil.getRequest().getQueryString()); + SaHolder.getResponse().redirect("/sso/login?back=" + SaFoxUtil.encodeUrl(back)); + SaRouter.back(); + } + }) + ; + } +} +``` + + +更多登录姿势可以参考 [[何时引导用户去登录]](/sso/sso-custom-login) 给出的建议进行设计。 + + ### 问:如果 sso-client 端我没有集成 sa-token-sso,如何对接? 需要手动调用 http 请求来对接 sso-server 开放的接口,参考示例:[sa-token-demo-sso3-client-nosdk](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-sso3-client-nosdk) @@ -53,6 +120,10 @@ SSO 集成常见问题整理 [SSO-Server 认证中心开放接口](/sso/sso-apidoc) +### 问:将旧有系统改造为单点登录时,应该注意哪些? +答:建议不要把其中一个系统改造为SSO服务端,而是新起一个项目作为 SSO-Server 端,所有旧有项目全部作为 Client 端与此对接。 + + ### 问:怎么在一个项目里同时搭建 sso-server 和 sso-client? 难点在于解决两边的路由冲突,示例代码: @@ -141,7 +212,7 @@ public class SsoUserServerController { public Object ssoUserRequest(String name, String pwd) { if("sa".equals(name) && "123456".equals(pwd)) { StpUserUtil.login(10001); - return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue()); + return SaResult.ok("登录成功!").setData(StpUserUtil.getTokenValue()); } return SaResult.error("登录失败!"); } diff --git a/sa-token-doc/sso/sso-type2.md b/sa-token-doc/sso/sso-type2.md index 9139591a..a38f3153 100644 --- a/sa-token-doc/sso/sso-type2.md +++ b/sa-token-doc/sso/sso-type2.md @@ -3,7 +3,7 @@ 如果我们的多个系统:部署在不同的域名之下,但是后端可以连接同一个Redis,那么便可以使用 **`[URL重定向传播会话]`** 的方式做到单点登录。 -### 1、解题思路 +### 1、设计思路 首先我们再次复习一下,多个系统之间为什么无法同步登录状态? diff --git a/sa-token-doc/up/not-cookie.md b/sa-token-doc/up/not-cookie.md index ae6059d9..e657d550 100644 --- a/sa-token-doc/up/not-cookie.md +++ b/sa-token-doc/up/not-cookie.md @@ -1,16 +1,16 @@ -# 前后台分离(无Cookie模式) +# 前后端分离(无Cookie模式) --- ### 何为无 Cookie 模式? -无 Cookie 模式:特指不支持 Cookie 功能的终端,通俗来讲就是我们常说的 —— **前后台分离模式**。 +无 Cookie 模式:特指不支持 Cookie 功能的终端,通俗来讲就是我们常说的 —— **前后端分离模式**。 常规 Web 端鉴权方法,一般由 `Cookie模式` 完成,而 Cookie 有两个特性: 1. 可由后端控制写入。 2. 每次请求自动提交。 这就使得我们在前端代码中,无需任何特殊操作,就能完成鉴权的全部流程(因为整个流程都是后端控制完成的)
-而在app、小程序等前后台分离场景中,一般是没有 Cookie 这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊? +而在app、小程序等前后端分离场景中,一般是没有 Cookie 这一功能的,此时大多数人都会一脸懵逼,咋进行鉴权啊? 见招拆招,其实答案很简单: - 不能后端控制写入了,就前端自己写入。(难点在**后端如何将 Token 传递到前端**) diff --git a/sa-token-doc/up/remember-me.md b/sa-token-doc/up/remember-me.md index d97e903e..29163904 100644 --- a/sa-token-doc/up/remember-me.md +++ b/sa-token-doc/up/remember-me.md @@ -33,11 +33,11 @@ Cookie作为浏览器提供的默认会话跟踪机制,其生命周期有两 -### 前后台分离模式下如何实现[记住我]? +### 前后端分离模式下如何实现[记住我]? 此时机智的你😏很快发现一个问题,Cookie虽好,却无法在前后端分离环境下使用,那是不是代表上述方案在APP、小程序等环境中无效? -准确的讲,答案是肯定的,任何基于Cookie的认证方案在前后台分离环境下都会失效(原因在于这些客户端默认没有实现Cookie功能),不过好在,这些客户端一般都提供了替代方案, +准确的讲,答案是肯定的,任何基于Cookie的认证方案在前后端分离环境下都会失效(原因在于这些客户端默认没有实现Cookie功能),不过好在,这些客户端一般都提供了替代方案, 唯一遗憾的是,此场景中token的生命周期需要我们在前端手动控制: 以经典跨端框架 [uni-app](https://uniapp.dcloud.io/) 为例,我们可以使用如下方式达到同样的效果: @@ -49,7 +49,7 @@ uni.setStorageSync("satoken", "xxxx-xxxx-xxxx-xxxx-xxx"); getApp().globalData.satoken = "xxxx-xxxx-xxxx-xxxx-xxx"; ``` -如果你决定在PC浏览器环境下进行前后台分离模式开发,那么更加简单: +如果你决定在PC浏览器环境下进行前后端分离模式开发,那么更加简单: ``` js // 使用 localStorage 保存token,达到 [持久Cookie] 的效果 localStorage.setItem("satoken", "xxxx-xxxx-xxxx-xxxx-xxx");