+ |
+
+ |
+
+ |
+
+ |
+ + |
+ Gitee + GitHub + 官网 |
-以Maven + SpringBoot为例 +整合示例在官方仓库的`/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习 --- +### 1、创建项目 +在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-springboot`(不会的同学请自行百度或者参考github示例) -## SpringBoot环境 -#### 1、创建项目 -在IDE中新建一个Springboot项目,例如:`sa-token-demo-springboot`(不会的同学请自行百度或者参考github示例) - -#### 2、设置jar包依赖 +### 2、设置pom包依赖 在 `pom.xml` 中添加依赖: ``` xml - + -但同时你也可以在`application.yml`中增加如下配置,定制性使用框架: + +### 3、设置配置文件 +你可以**零配置启动项目** ,但同时你也可以在`application.yml`中增加如下配置,定制性使用框架: ``` java spring: @@ -49,7 +47,7 @@ spring: 百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) -#### 4、创建启动类 +### 4、创建启动类 在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,输入以下代码: ``` java @@ -62,18 +60,18 @@ public class SaTokenDemoApplication { } ``` -#### 5、运行 +### 5、运行 运行代码,当你从控制台看到类似下面的内容时,就代表框架已经成功集成了  -## 普通Spring环境 +### 普通Spring环境 普通spring环境与springboot环境大体无异,只不过需要在项目根目录手动创建配置文件`sa-token.properties`来完成配置 -## 详细了解 -通过这个示例,你已经对sa-token有了初步的了解,那么现在开始详细了解一下它都有哪些[能力](/use/login-auth)吧 +### 详细了解 +通过这个示例,你已经对sa-token有了初步的了解,那么现在开始详细了解一下它都有哪些 [能力](/use/login-auth) 吧 diff --git a/sa-token-doc/doc/start/webflux-example.md b/sa-token-doc/doc/start/webflux-example.md new file mode 100644 index 00000000..002968d5 --- /dev/null +++ b/sa-token-doc/doc/start/webflux-example.md @@ -0,0 +1,76 @@ +# Spring WebFlux 集成 Sa-Token 示例 + +WebFlux基于Reactor响应式模型开发,有着与标准ServletAPI完全不同的底层架构,因此要适配WebFlux, 必须提供与Reactor相关的整合实现, +本篇将以WebFlux为例,展示sa-token与Reactor响应式模型web框架相整合的示例, **你可以用同样方式去对接其它Reactor模型Web框架** + +整合示例在官方仓库的`/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习 + + +--- + +### 1、创建项目 +在IDE中新建一个SpringBoot项目,例如:`sa-token-demo-webflux`(不会的同学请自行百度或者参考github示例) + + +### 2、设置pom包依赖 +在 `pom.xml` 中添加依赖: + +``` xml + + +百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) + + +### 4、创建启动类 +在项目中新建包 `com.pj` ,在此包内新建主类 `SaTokenDemoApplication.java`,输入以下代码: + +``` java +@SpringBootApplication +public class SaTokenDemoApplication { + public static void main(String[] args) throws JsonProcessingException { + SpringApplication.run(SaTokenDemoApplication.class, args); + System.out.println("启动成功:sa-token配置如下:" + SaTokenManager.getConfig()); + } +} +``` + +### 5、运行 +运行代码,当你从控制台看到类似下面的内容时,就代表框架已经成功集成了 + + + + + + + + + diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md index 25b81c8f..161b0d69 100644 --- a/sa-token-doc/doc/use/at-check.md +++ b/sa-token-doc/doc/use/at-check.md @@ -84,11 +84,11 @@ mode有两种取值: ## 2、使用拦截器模式 使用AOP方式需要引入新的pom依赖,与此相比,拦截器模式显的更加轻量级 你只需要将sa-token的注解校验拦截器注册到你的项目中即可打开注解鉴权功能 -以`SpringBoot2.0`为例, 新建配置类`MySaTokenConfig.java` +以`SpringBoot2.0`为例, 新建配置类`SaTokenConfigure.java` ``` java @Configuration -public class MySaTokenConfig implements WebMvcConfigurer { +public class SaTokenConfigure implements WebMvcConfigurer { // 注册sa-token的注解拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index 6e539475..79d9b887 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -35,11 +35,11 @@ spring: * sa-token代码方式进行配置 */ @Configuration -public class MySaTokenConfig { +public class SaTokenConfigure { // 获取配置Bean (以代码的方式配置sa-token, 此配置会覆盖yml中的配置) @Primary - @Bean(name="MySaTokenConfig") + @Bean(name="SaTokenConfigure") public SaTokenConfig getSaTokenConfig() { SaTokenConfig config = new SaTokenConfig(); config.setTokenName("satoken"); // token名称 (同时也是cookie名称) diff --git a/sa-token-doc/doc/use/global-filter.md b/sa-token-doc/doc/use/global-filter.md new file mode 100644 index 00000000..9a9bb825 --- /dev/null +++ b/sa-token-doc/doc/use/global-filter.md @@ -0,0 +1,103 @@ +# 全局过滤器 +--- + +### 组件简述 + +上一节,我们学习了“根据拦截器实现路由拦截鉴权”,其实在大多数web框架中,使用过滤器可以实现同样的功能,本章我们就利用sa-token全局过滤器来实现路由拦截器鉴权。 + +首先我们先梳理清楚一个问题,既然拦截器已经可以实现路由鉴权,为什么还要用过滤器再实现一遍呢?简而言之: +1. 相比于拦截器,过滤器更加底层,执行时机更靠前,有利于防渗透扫描 +2. 过滤器可以拦截静态资源,方便我们做一些权限控制 +3. 部分Web框架根本就没有提供拦截器功能,但几乎所有的Web框架都会提供过滤器机制 + +但是过滤器也有一些缺点,比如: +1. 由于太过底层,导致无法率先拿到`HandlerMethod`对象,无法据此添加一些额外功能 +2. 由于拦截的太全面了,导致我们需要对很多特殊路由(如`/favicon.ico`)做一些额外处理 +3. 在Spring中,过滤器中抛出的异常无法进入全局`@ExceptionHandler`,我们必须额外编写代码进行异常处理 + +Sa-Token同时提供过滤器和拦截器机制,不是为了让谁替代谁,而是为了让大家根据自己的实际业务合理选择,拥有更多的发挥空间。 + + +### 注册过滤器 +同拦截器一样,为了避免不必要的性能浪费,sa-token全局过滤器默认处于关闭状态,若要使用过滤器组件,首先你需要注册它到项目中: +``` java +/** + * [Sa-Token 权限认证] 配置类 + * @author kong + */ +@Configuration +public class SaTokenConfigure { + + /** + * 注册 [sa-token全局过滤器] + */ + @Bean + public SaServletFilter getSaReactorFilter() { + return new SaServletFilter(); + } + + /** + * 注册 [sa-token全局过滤器-认证策略] + */ + @Bean + public SaFilterStrategy getSaFilterStrategy() { + return r -> { + System.out.println("---------- 进入sa-token全局过滤器 -----------"); + + // 登录验证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 + SaRouterUtil.match("/**", "/user/doLogin", () -> StpUtil.checkLogin()); + + // 权限认证 -- 不同模块, 校验不同权限 + SaRouterUtil.match("/user/**", () -> StpUtil.checkPermission("user")); + SaRouterUtil.match("/admin/**", () -> StpUtil.checkPermission("admin")); + SaRouterUtil.match("/goods/**", () -> StpUtil.checkPermission("goods")); + SaRouterUtil.match("/orders/**", () -> StpUtil.checkPermission("orders")); + SaRouterUtil.match("/notice/**", () -> StpUtil.checkPermission("notice")); + SaRouterUtil.match("/comment/**", () -> StpUtil.checkPermission("comment")); + + // 匹配 restful 风格路由 + SaRouterUtil.match("/article/get/{id}", () -> StpUtil.checkPermission("article")); + }; + } + + /** + * 注册 [sa-token全局过滤器-异常处理策略] + */ + @Bean + public SaFilterErrorStrategy getSaFilterErrorStrategy() { + return e -> AjaxJson.getError(e.getMessage()); + } + +} +``` + +### 注意事项 +- 在`[认证策略]`里,你可以和拦截器里一致的代码,进行路由匹配鉴权 +- 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理策略]`来处理`[认证策略]`里抛出的异常 +- 在`[异常处理策略]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换 + + +### 在WebFlux中使用过滤器 +`Spring WebFlux`中不提供拦截器机制,因此若你的项目需要路由鉴权功能,过滤器是你唯一的选择,在`Spring WebFlux`注册过滤器的流程与上述流程几乎完全一致, +除了您需要将过滤器名称由`SaServletFilter`更换为`SaReactorFilter`以外,其它所有步骤均可参考以上示例 +``` java +/** + * [Sa-Token 权限认证] 配置类 + * @author kong + */ +@Configuration +public class SaTokenConfigure { + + /** + * 注册 [sa-token全局过滤器] + */ + @Bean + public SaReactorFilter getSaReactorFilter() { + return new SaReactorFilter(); + } + + // 其它代码 ... + +} +``` + \ No newline at end of file diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md index e9d87b0d..f4627456 100644 --- a/sa-token-doc/doc/use/route-check.md +++ b/sa-token-doc/doc/use/route-check.md @@ -10,10 +10,10 @@ ## 1、注册路由拦截器 -以`SpringBoot2.0`为例, 新建配置类`MySaTokenConfig.java` +以`SpringBoot2.0`为例, 新建配置类`SaTokenConfigure.java` ``` java @Configuration -public class MySaTokenConfig implements WebMvcConfigurer { +public class SaTokenConfigure implements WebMvcConfigurer { // 注册sa-token的登录拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { @@ -31,7 +31,7 @@ public class MySaTokenConfig implements WebMvcConfigurer { ``` java @Configuration -public class MySaTokenConfig implements WebMvcConfigurer { +public class SaTokenConfigure implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义验证规则 @@ -53,7 +53,7 @@ public class MySaTokenConfig implements WebMvcConfigurer { ``` java @Configuration -public class MySaTokenConfig implements WebMvcConfigurer { +public class SaTokenConfigure implements WebMvcConfigurer { // 注册sa-token的拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { diff --git a/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorFilter.java b/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java similarity index 91% rename from sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorFilter.java rename to sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java index 57c48f21..8e5eae3e 100644 --- a/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorFilter.java +++ b/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java @@ -1,4 +1,4 @@ -package cn.dev33.satoken.reactor.context; +package cn.dev33.satoken.reactor.filter; import org.springframework.core.annotation.Order; import org.springframework.web.server.ServerWebExchange; @@ -6,6 +6,8 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import cn.dev33.satoken.SaTokenManager; +import cn.dev33.satoken.reactor.context.SaReactorHolder; +import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.util.SaTokenConsts; import reactor.core.publisher.Mono; diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java new file mode 100644 index 00000000..579bdcd0 --- /dev/null +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java @@ -0,0 +1,56 @@ +package cn.dev33.satoken.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.springframework.core.annotation.Order; + +import cn.dev33.satoken.SaTokenManager; +import cn.dev33.satoken.util.SaTokenConsts; + +/** + * Servlet全局过滤器 + * @author kong + * + */ +@Order(SaTokenConsts.ASSEMBLY_ORDER) +public class SaServletFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + try { + // 执行全局过滤器 + SaTokenManager.getSaFilterStrategy().run(null); + + } catch (Throwable e) { + // 1. 获取异常处理策略结果 + Object result = SaTokenManager.getSaFilterErrorStrategy().run(e); + String resultString = String.valueOf(result); + + // 2. 写入输出流 + response.setContentType("text/plain; charset=utf-8"); + response.getWriter().print(resultString); + return; + } + + // 执行 + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void destroy() { + } + +} |