Spring Boot 中实现全局 Token 验证的两种方式
文章目录
- 学习文章:Spring Boot 中实现全局 Token 验证的两种方式
- 一、为什么需要全局 Token 验证?
- 二、使用拦截器实现全局 Token 验证
- 1. 创建 Token 验证拦截器
- 2. 注册拦截器
- 3. 测试拦截器
- 三、使用过滤器实现全局 Token 验证
- 1. 创建 Token 验证过滤器
- 2. 注册过滤器
- 3. 测试过滤器
- 四、拦截器 vs 过滤器
- 1. **拦截器的优势**
- 2. **过滤器的优势**
- 3. **选择建议**
- 五、全局异常处理
- 1. 定义统一响应格式
- 2. 全局异常处理器
- 3. 在拦截器或过滤器中抛出异常
- 六、总结
学习文章:Spring Boot 中实现全局 Token 验证的两种方式
在 Spring Boot 项目中,Token 验证是保护接口安全的常见手段。如果每个接口都单独编写 Token 验证逻辑,会导致代码冗余且难以维护。为了解决这个问题,可以通过 拦截器(Interceptor) 或 过滤器(Filter) 实现全局 Token 验证,从而统一处理所有接口的验证逻辑。
本文将详细介绍如何使用拦截器和过滤器实现全局 Token 验证,并提供完整的代码示例和最佳实践。
一、为什么需要全局 Token 验证?
在前后端分离的架构中,客户端通常通过 Token 进行身份验证。如果每个接口都单独验证 Token,会导致以下问题:
- 代码冗余:每个接口都需要编写重复的验证逻辑。
- 维护困难:当验证逻辑需要修改时,需要修改所有相关接口。
- 容易遗漏:新增接口时可能会忘记添加验证逻辑,导致安全漏洞。
通过全局 Token 验证,可以统一处理所有接口的验证逻辑,提高代码的复用性和可维护性。
二、使用拦截器实现全局 Token 验证
拦截器是 Spring MVC 提供的一种机制,可以在请求到达控制器之前或之后执行特定的逻辑。以下是实现步骤:
1. 创建 Token 验证拦截器
创建一个拦截器类,实现 HandlerInterceptor
接口,并在 preHandle
方法中编写 Token 验证逻辑。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从请求头中获取 Token
String token = request.getHeader("Authorization");
// 验证 Token
if (token == null || !isValidToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 未授权
response.getWriter().write("Token 无效或未提供");
return false; // 中断请求
}
return true; // 继续执行请求
}
// 模拟 Token 验证逻辑
private boolean isValidToken(String token) {
// 这里可以调用具体的 Token 验证服务
return "valid-token".equals(token);
}
}
2. 注册拦截器
将拦截器注册到 Spring MVC 中,并配置需要拦截的路径。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有路径
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**") // 拦截所有接口
.excludePathPatterns("/login", "/register"); // 排除不需要拦截的路径
}
}
3. 测试拦截器
启动项目后,访问任意接口时,如果请求头中没有提供有效的 Token,则会返回 401 错误。
三、使用过滤器实现全局 Token 验证
过滤器是 Servlet 提供的一种机制,可以在请求到达 Spring MVC 之前执行逻辑。以下是实现步骤:
1. 创建 Token 验证过滤器
创建一个过滤器类,实现 Filter
接口,并在 doFilter
方法中编写 Token 验证逻辑。
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TokenFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 从请求头中获取 Token
String token = httpRequest.getHeader("Authorization");
// 验证 Token
if (token == null || !isValidToken(token)) {
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 未授权
httpResponse.getWriter().write("Token 无效或未提供");
return; // 中断请求
}
chain.doFilter(request, response); // 继续执行请求
}
// 模拟 Token 验证逻辑
private boolean isValidToken(String token) {
// 这里可以调用具体的 Token 验证服务
return "valid-token".equals(token);
}
}
2. 注册过滤器
将过滤器注册到 Spring Boot 中,并配置需要拦截的路径。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<TokenFilter> tokenFilter() {
FilterRegistrationBean<TokenFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TokenFilter());
registrationBean.addUrlPatterns("/*"); // 拦截所有路径
registrationBean.setOrder(1); // 设置过滤器顺序
return registrationBean;
}
}
3. 测试过滤器
启动项目后,访问任意接口时,如果请求头中没有提供有效的 Token,则会返回 401 错误。
四、拦截器 vs 过滤器
1. 拦截器的优势
- 与 Spring MVC 深度集成,可以访问 Spring 的上下文和 Bean。
- 可以精确控制拦截的路径(通过
addPathPatterns
和excludePathPatterns
)。 - 适合处理与业务逻辑相关的拦截(如权限验证、日志记录)。
2. 过滤器的优势
- 更底层,可以拦截所有请求(包括静态资源)。
- 适合处理与 Servlet 相关的逻辑(如编码设置、跨域处理)。
3. 选择建议
- 如果需要在 Spring MVC 的上下文中处理逻辑(如依赖注入),优先使用拦截器。
- 如果需要拦截所有请求(包括静态资源),或者需要更底层的控制,优先使用过滤器。
五、全局异常处理
在拦截器或过滤器中,如果验证失败,直接返回错误响应可能会导致客户端无法解析。可以通过全局异常处理机制统一返回 JSON 格式的错误信息。
1. 定义统一响应格式
public class ApiResponse {
private boolean status;
private int code;
private String message;
// 构造方法和 Getter/Setter 省略
}
2. 全局异常处理器
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UnauthorizedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ApiResponse handleUnauthorizedException(UnauthorizedException e) {
return new ApiResponse(false, 401, e.getMessage());
}
}
3. 在拦截器或过滤器中抛出异常
if (token == null || !isValidToken(token)) {
throw new UnauthorizedException("Token 无效或未提供");
}
六、总结
通过拦截器或过滤器,可以轻松实现 Spring Boot 项目中所有接口的 Token 验证。以下是两种方式的对比:
特性 | 拦截器(Interceptor) | 过滤器(Filter) |
---|---|---|
集成方式 | Spring MVC 集成 | Servlet 集成 |
拦截范围 | 只能拦截 Spring MVC 的请求 | 可以拦截所有请求(包括静态资源) |
依赖注入 | 支持 | 不支持 |
适用场景 | 业务逻辑相关的拦截(如权限验证) | 底层逻辑相关的拦截(如编码设置) |
根据项目需求选择合适的方式,并结合全局异常处理机制,可以构建一个健壮且易维护的 Token 验证系统。希望本文对你有所帮助!