《课次29:拦截器实现Token校验 + ThreadLocal》学习笔记

一、教学目标

  1. 创建拦截器,对除登录、注册外的接口进行 Token 校验。
  2. 使用 ThreadLocal 存储当前登录用户的 ID,便于在后续业务处理中获取用户信息。

二、核心知识点

知识点 说明
HandlerInterceptor Spring MVC 提供的拦截器接口,可在请求处理前后执行自定义逻辑
ThreadLocal 线程局部变量,每个线程独立存储数据,互不干扰,适合存放当前请求的用户信息
Token 校验 从请求头获取 Token,解析验证其有效性,无效时返回 401 状态码

三、操作步骤

本课次是在课次28的工程基础上继续操作。
1. 创建 UserContext 工具类

  • util 文件夹下新建 Java 类 UserContext
  • 代码如下:
package com.weitoutiao.util;
public class UserContext {
    private static final ThreadLocal<Integer> currentUserId = new ThreadLocal<>();
    public static void setCurrentUserId(Integer userId) {
        currentUserId.set(userId);
    }
    public static Integer getCurrentUserId() {
        return currentUserId.get();
    }
    public static void clear() {
        currentUserId.remove();
    }
}

说明ThreadLocal 为每个线程独立存储数据,不同线程之间的数据互不干扰。
2. 创建 JwtInterceptor 拦截器

  • com.weitoutiao 下新建 interceptor.JwtInterceptor
  • 代码如下:
package com.weitoutiao.interceptor;
import com.weitoutiao.util.JwtUtil;
import com.weitoutiao.util.UserContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtil jwtUtil;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 从请求头中获取 Authorization
        String token = request.getHeader("Authorization");  
        // 2. 校验 Token 是否存在且以 "Bearer " 开头
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);  // 去掉 "Bearer " 前缀
            // 3. 验证 Token 是否有效
            if (jwtUtil.validateToken(token)) {
                Integer userId = jwtUtil.getUserIdFromToken(token);
                // 4. 将用户 ID 存入 ThreadLocal
                UserContext.setCurrentUserId(userId);
                return true;  // 放行
            }
        }   
        // 5. Token 无效或缺失,返回 401 未授权
        response.setStatus(401);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("{\"code\":401,\"message\":\"未登录或token失效\"}");
        return false;  // 拦截
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成后,清除 ThreadLocal 中的数据,防止内存泄漏
        UserContext.clear();
    }
}

说明

  • preHandle 在请求处理之前执行,负责 Token 校验。
  • afterCompletion 在视图渲染之后(即整个请求处理完毕)执行,用于清理 ThreadLocal 资源。
    3. 配置拦截器
  • config 文件夹下新建 Java 类 InterceptorConfig
  • 代码如下:
package com.weitoutiao.config;
import com.weitoutiao.interceptor.JwtInterceptor;
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 InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private JwtInterceptor jwtInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")                      // 拦截所有请求
                .excludePathPatterns("/user/login", "/user/register");  // 排除登录和注册接口
    }
}

说明

  • addPathPatterns("/**"):拦截所有路径的请求。
  • excludePathPatterns(...):排除登录和注册接口,这些接口不需要 Token 验证。
    4. 本课次的工程目录结构
com.weitoutiao
├── common
│   ├── GlobalExceptionHandler
│   └── Result
├── config
│   ├── InterceptorConfig          ← 新增
│   ├── MyBatisPlusConfig
│   └── MyMetaObjectHandler
├── controller
│   ├── HelloController
│   └── UserController
├── dto
│   └── UserLoginDTO
├── entity
│   ├── News
│   └── User
├── interceptor                    ← 新增包
│   └── JwtInterceptor             ← 新增
├── mapper
│   ├── NewsMapper
│   └── UserMapper
├── service
│   ├── UserService
│   └── impl
│       ├── NewsServiceImpl
│       └── UserServiceImpl
├── util
│   ├── JwtUtil
│   └── UserContext                ← 新增
└── WeiTouTiaoSpringBootApplication

四、笔记总结

步骤 核心内容
UserContext 使用 ThreadLocal 存储当前用户 ID,提供 setgetclear 方法
JwtInterceptor 实现 HandlerInterceptor,在 preHandle 中从请求头获取并校验 Token
Token 提取 Authorization 头中获取,去掉 Bearer 前缀后再验证
用户信息存储 验证通过后,将用户 ID 存入 ThreadLocal,供后续业务使用
资源清理 afterCompletion 中调用 UserContext.clear() 移除线程局部变量
拦截器配置 通过 InterceptorConfig 注册拦截器,配置拦截路径和排除路径
本课次完成了 Token 校验拦截器的实现,自此“微头条”项目的登录认证体系已完整闭环:
  • 课次28:用户登录 → 生成 JWT Token
  • 课次29:请求受保护接口 → 拦截器校验 Token → 通过则放行并将用户信息存入 ThreadLocal
posted @ 2026-06-29 13:10  WJX-nb666  阅读(1)  评论(0)    收藏  举报