1. JWT(JSON Web Token)
核心概念
-
作用:轻量级身份验证和授权机制,替代传统的Session。
-
结构:
Header.Payload.Signature
- Header:算法类型(如HS256)和Token类型(JWT)。
- Payload:用户信息(如用户ID、角色)、过期时间等。
- Signature:对Header和Payload的签名,防篡改。
-
流程:
- 用户登录后,服务端生成JWT返回给客户端。
- 客户端后续请求携带JWT(通常放在
Authorization
头)。 - 服务端验证JWT合法性并解析用户信息。
示例代码(使用 jjwt
库)
public class JwtUtils {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION = 86400000; // 24小时
// 生成JWT
public static String generateToken(String username, List<String> roles) {
return Jwts.builder()
.setSubject(username)
.claim("roles", roles)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 解析JWT
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
2. 过滤器(Filter)
核心概念
-
作用:在请求进入Servlet前预处理(如身份验证、日志记录)。
-
执行位置:Servlet容器层(Tomcat/Jetty)。
-
特点:可拦截所有请求(包括静态资源)。
-
常见用途:
- 身份验证(如JWT校验)。
- 请求日志记录。
- 字符编码处理。
示例代码(JWT认证过滤器)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
try {
Claims claims = JwtUtils.parseToken(token);
String username = claims.getSubject();
List<String> roles = claims.get("roles", List.class);
// 构建Spring Security认证对象
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
username, null, roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())
);
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return;
}
}
filterChain.doFilter(request, response);
}
}
3. 拦截器(Interceptor)
核心概念
-
作用:在Controller方法执行前后处理逻辑(如权限校验、参数预处理)。
-
执行位置:Spring MVC层(DispatcherServlet之后)。
-
特点:可访问Spring上下文(如Controller、Service)。
-
常见用途:
- 接口访问频率控制。
- 参数校验。
- 动态权限控制。
示例代码(权限拦截器)
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 检查用户权限(如是否拥有特定角色)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.getAuthorities().contains(new SimpleGrantedAuthority("ADMIN"))) {
response.setStatus(HttpStatus.FORBIDDEN.value());
return false;
}
return true;
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/admin/**");
}
}
4. 全局异常处理器
核心概念
-
作用:统一处理Controller层抛出的异常,返回标准化错误响应。
-
核心注解:
@ControllerAdvice
:声明全局异常处理器。@ExceptionHandler
:定义处理特定异常的方法。
示例代码
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理认证异常
@ExceptionHandler(AuthenticationException.class)
@ResponseBody
public ResponseEntity<?> handleAuthException(AuthenticationException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("error", e.getMessage()));
}
// 处理其他未知异常
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<?> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", "Internal Server Error"));
}
}
协作关系与执行顺序
-
请求流程:
Filter(JWT校验) → Interceptor(权限检查) → Controller → 全局异常处理器 -
异常处理:
- Filter和Interceptor中的异常默认不会由
@ControllerAdvice
捕获。 - 需在Filter中通过
try-catch
处理异常或自定义异常转发。
- Filter和Interceptor中的异常默认不会由
关键对比
组件 | 执行层级 | 是否依赖Spring | 典型用途 |
---|---|---|---|
Filter | Servlet容器层 | 否 | 全局请求处理(如JWT校验) |
Interceptor | Spring MVC层 | 是 | 细粒度权限控制、日志记录 |
@ControllerAdvice | Spring MVC层 | 是 | 统一异常处理、响应格式化 |
完整流程示例
- 用户登录:生成JWT并返回。
- 请求携带JWT:客户端在
Authorization
头中添加Bearer <token>
。 - JWT过滤器:解析Token并设置Spring Security上下文。
- 拦截器:检查用户权限,决定是否放行。
- Controller:执行业务逻辑。
- 异常处理:若Controller抛出异常,由
@ControllerAdvice
统一处理。
最佳实践
-
JWT安全:
- 使用HTTPS传输。
- 设置合理的过期时间。
- 避免在JWT中存储敏感信息。
-
过滤器 vs 拦截器:
- 优先用拦截器处理与Spring相关的逻辑(如依赖注入)。
- 过滤器处理底层Servlet逻辑(如编码、跨域)。
-
异常处理:
- 在Filter中手动处理异常并返回标准响应。
- 使用
@ControllerAdvice
统一格式化错误响应。