mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-02-27 16:50:24 +08:00
适配 springboot3
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.factorypath
|
||||
|
||||
.idea/
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>sa-token-spring-boot3-starter</name>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<description>springboot3 integrate sa-token</description>
|
||||
|
||||
<properties>
|
||||
<springboot3.version>3.0.1</springboot3.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- spring-boot-starter-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- config (optional) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token-jakarta-servlet -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jakarta-servlet</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token-spring-boot-autoconfig -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-autoconfig</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<!-- spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<version>${springboot3.version}</version>
|
||||
</dependency>
|
||||
<!-- spring-boot-starter-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${springboot3.version}</version>
|
||||
</dependency>
|
||||
<!-- config (optional) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<version>${springboot3.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
</project>
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
package cn.dev33.satoken.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import cn.dev33.satoken.error.SaSpringBootErrorCode;
|
||||
import cn.dev33.satoken.exception.BackResultException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.exception.StopMatchException;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* Servlet全局过滤器
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Order(SaTokenConsts.ASSEMBLY_ORDER)
|
||||
public class SaServletFilter implements Filter {
|
||||
|
||||
// ------------------------ 设置此过滤器 拦截 & 放行 的路由
|
||||
|
||||
/**
|
||||
* 拦截路由
|
||||
*/
|
||||
private List<String> includeList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 放行路由
|
||||
*/
|
||||
private List<String> excludeList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 添加 [拦截路由]
|
||||
* @param paths 路由
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter addInclude(String... paths) {
|
||||
includeList.addAll(Arrays.asList(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 [放行路由]
|
||||
* @param paths 路由
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter addExclude(String... paths) {
|
||||
excludeList.addAll(Arrays.asList(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 [拦截路由] 集合
|
||||
* @param pathList 路由集合
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter setIncludeList(List<String> pathList) {
|
||||
includeList = pathList;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 [放行路由] 集合
|
||||
* @param pathList 路由集合
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter setExcludeList(List<String> pathList) {
|
||||
excludeList = pathList;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 [拦截路由] 集合
|
||||
* @return see note
|
||||
*/
|
||||
public List<String> getIncludeList() {
|
||||
return includeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 [放行路由] 集合
|
||||
* @return see note
|
||||
*/
|
||||
public List<String> getExcludeList() {
|
||||
return excludeList;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ 钩子函数
|
||||
|
||||
/**
|
||||
* 认证函数:每次请求执行
|
||||
*/
|
||||
public SaFilterAuthStrategy auth = r -> {};
|
||||
|
||||
/**
|
||||
* 异常处理函数:每次[认证函数]发生异常时执行此函数
|
||||
*/
|
||||
public SaFilterErrorStrategy error = e -> {
|
||||
throw new SaTokenException(e).setCode(SaSpringBootErrorCode.CODE_20105);
|
||||
};
|
||||
|
||||
/**
|
||||
* 前置函数:在每次[认证函数]之前执行
|
||||
*/
|
||||
public SaFilterAuthStrategy beforeAuth = r -> {};
|
||||
|
||||
/**
|
||||
* 写入[认证函数]: 每次请求执行
|
||||
* @param auth see note
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter setAuth(SaFilterAuthStrategy auth) {
|
||||
this.auth = auth;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入[异常处理函数]:每次[认证函数]发生异常时执行此函数
|
||||
* @param error see note
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter setError(SaFilterErrorStrategy error) {
|
||||
this.error = error;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入[前置函数]:在每次[认证函数]之前执行
|
||||
* @param beforeAuth see note
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaServletFilter setBeforeAuth(SaFilterAuthStrategy beforeAuth) {
|
||||
this.beforeAuth = beforeAuth;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ doFilter
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
try {
|
||||
// 执行全局过滤器
|
||||
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
|
||||
beforeAuth.run(null);
|
||||
auth.run(null);
|
||||
});
|
||||
|
||||
} catch (StopMatchException e) {
|
||||
|
||||
} catch (Throwable e) {
|
||||
// 1. 获取异常处理策略结果
|
||||
String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
|
||||
|
||||
// 2. 写入输出流
|
||||
if(response.getContentType() == null) {
|
||||
response.setContentType("text/plain; charset=utf-8");
|
||||
}
|
||||
response.getWriter().print(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package cn.dev33.satoken.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.exception.BackResultException;
|
||||
import cn.dev33.satoken.exception.StopMatchException;
|
||||
import cn.dev33.satoken.fun.SaParamFunction;
|
||||
import cn.dev33.satoken.strategy.SaStrategy;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-8-21
|
||||
*/
|
||||
public class SaInterceptor implements HandlerInterceptor {
|
||||
|
||||
/**
|
||||
* 是否打开注解鉴权
|
||||
*/
|
||||
public boolean isAnnotation = true;
|
||||
|
||||
/**
|
||||
* 认证函数:每次请求执行
|
||||
* <p> 参数:路由处理函数指针
|
||||
*/
|
||||
public SaParamFunction<Object> auth = handler -> {};
|
||||
|
||||
/**
|
||||
* 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力
|
||||
*/
|
||||
public SaInterceptor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力
|
||||
* @param auth 认证函数,每次请求执行
|
||||
*/
|
||||
public SaInterceptor(SaParamFunction<Object> auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否打开注解鉴权
|
||||
* @param isAnnotation /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaInterceptor isAnnotation(boolean isAnnotation) {
|
||||
this.isAnnotation = isAnnotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入[认证函数]: 每次请求执行
|
||||
* @param auth /
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaInterceptor setAuth(SaParamFunction<Object> auth) {
|
||||
this.auth = auth;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ----------------- 验证方法 -----------------
|
||||
|
||||
/**
|
||||
* 每次请求之前触发的方法
|
||||
*/
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
|
||||
try {
|
||||
|
||||
if(isAnnotation && handler instanceof HandlerMethod) {
|
||||
|
||||
// 获取此请求对应的 Method 处理函数
|
||||
Method method = ((HandlerMethod) handler).getMethod();
|
||||
|
||||
// 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权
|
||||
if(SaStrategy.me.isAnnotationPresent.apply(method, SaIgnore.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 注解校验
|
||||
SaStrategy.me.checkMethodAnnotation.accept(method);
|
||||
}
|
||||
|
||||
// Auth 校验
|
||||
auth.run(handler);
|
||||
|
||||
} catch (StopMatchException e) {
|
||||
// 停止匹配,进入Controller
|
||||
} catch (BackResultException e) {
|
||||
// 停止匹配,向前端输出结果
|
||||
if(response.getContentType() == null) {
|
||||
response.setContentType("text/plain; charset=utf-8");
|
||||
}
|
||||
response.getWriter().print(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 通过验证
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* sa-token集成SpringBoot的各个组件
|
||||
*/
|
||||
package cn.dev33.satoken;
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cn.dev33.satoken.spring;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContext;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
|
||||
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
|
||||
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [ SpringBoot3 Jakarta Servlet 版 ]
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextForSpringInJakartaServlet implements SaTokenContext {
|
||||
|
||||
/**
|
||||
* 获取当前请求的Request对象
|
||||
*/
|
||||
@Override
|
||||
public SaRequest getRequest() {
|
||||
return new SaRequestForServlet(SpringMVCUtil.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的Response对象
|
||||
*/
|
||||
@Override
|
||||
public SaResponse getResponse() {
|
||||
return new SaResponseForServlet(SpringMVCUtil.getResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [存储器] 对象
|
||||
*/
|
||||
@Override
|
||||
public SaStorage getStorage() {
|
||||
return new SaStorageForServlet(SpringMVCUtil.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
return SaPathMatcherHolder.getPathMatcher().match(pattern, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 此上下文是否有效
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return SpringMVCUtil.isWeb();
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.dev33.satoken.spring;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContext;
|
||||
|
||||
/**
|
||||
* SaTokenContext 上下文注册
|
||||
*
|
||||
* @author kong
|
||||
* @since 2023年1月1日
|
||||
*
|
||||
*/
|
||||
public class SaTokenContextRegister {
|
||||
|
||||
/**
|
||||
* 获取上下文Bean [ SpringBoot3 Jakarta Servlet 版 ]
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@Bean
|
||||
public SaTokenContext getSaTokenContextForSpringInJakartaServlet() {
|
||||
return new SaTokenContextForSpringInJakartaServlet();
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package cn.dev33.satoken.spring;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import cn.dev33.satoken.error.SaSpringBootErrorCode;
|
||||
import cn.dev33.satoken.exception.NotWebContextException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* SpringMVC相关操作
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SpringMVCUtil {
|
||||
|
||||
private SpringMVCUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的 request
|
||||
* @return request
|
||||
*/
|
||||
public static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if(servletRequestAttributes == null) {
|
||||
throw new NotWebContextException("非Web上下文无法获取Request").setCode(SaSpringBootErrorCode.CODE_20101);
|
||||
}
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前会话的 response
|
||||
* @return response
|
||||
*/
|
||||
public static HttpServletResponse getResponse() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if(servletRequestAttributes == null) {
|
||||
throw new NotWebContextException("非Web上下文无法获取Response").setCode(SaSpringBootErrorCode.CODE_20101);
|
||||
}
|
||||
return servletRequestAttributes.getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前是否处于 Web 上下文中
|
||||
* @return request
|
||||
*/
|
||||
public static boolean isWeb() {
|
||||
return RequestContextHolder.getRequestAttributes() != null;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
cn.dev33.satoken.spring.SaTokenContextRegister
|
||||
Reference in New Issue
Block a user