java springboot3 后端 基础框架

后端项目文件详解

这是一个基于 Spring Boot 3.2.0 的博客后端项目,使用 MySQL 数据库,实现了管理员登录认证功能。


📁 项目结构

复制代码
backend/
├── pom.xml                              # Maven 项目配置
├── src/main/java/com/blog/
│   ├── BlogApplication.java             # 启动类
│   ├── config/
│   │   ├── JwtAuthenticationFilter.java # JWT 认证过滤器
│   │   └── SecurityConfig.java          # Spring Security 配置
│   ├── controller/
│   │   └── AuthController.java          # 认证控制器
│   ├── entity/
│   │   └── AdminUser.java               # 管理员用户实体
│   ├── exception/
│   │   └── GlobalExceptionHandler.java  # 全局异常处理
│   ├── mapper/
│   │   └── AdminUserMapper.java         # 用户 Mapper
│   ├── service/
│   │   └── AuthService.java             # 认证服务
│   └── util/
│       └── JwtUtil.java                 # JWT 工具类
└── src/main/resources/
    ├── application.yml                  # 应用配置
    └── schema.sql                       # 数据库脚本

📄 详细文件说明

1. [pom.xml](file:///d:/0Document/project/Blog/backend/pom.xml) - Maven 项目配置

这是项目的依赖管理文件,定义了项目的基本信息和所有依赖。

主要配置:

配置项
Spring Boot 版本 3.2.0
Java 版本 17
项目版本 1.0.0

核心依赖:

依赖 用途
spring-boot-starter-web Web 开发(REST API)
spring-boot-starter-security 安全认证
mybatis-plus-spring-boot3-starter MyBatis Plus ORM 框架
mysql-connector-j MySQL 数据库驱动
jjwt (0.12.3) JWT Token 生成与解析
lombok 简化代码(自动生成 getter/setter)

2. [BlogApplication.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/BlogApplication.java) - 启动类

项目的入口类,使用 @SpringBootApplication 注解标注。

关键点:

  • @MapperScan("com.blog.mapper") - 自动扫描 Mapper 接口,简化数据库操作
java 复制代码
@SpringBootApplication
@MapperScan("com.blog.mapper")
public class BlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class, args);
    }
}

3. [JwtAuthenticationFilter.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/config/JwtAuthenticationFilter.java) - JWT 认证过滤器

这是一个 Spring Filter,每次请求都会经过此过滤器,用于验证 JWT Token。

工作流程:

复制代码
请求 → 提取 Header 中的 Bearer Token → 验证 Token → 解析用户信息 → 存入 request 属性 → 放行

核心逻辑:

  1. 从请求头 Authorization 中提取 Bearer {token}
  2. 调用 jwtUtil.validateToken(token) 验证 Token 有效性
  3. 解析出 userIdusername,存入 request.setAttribute()
  4. 放行请求到后续处理器

4. [SecurityConfig.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/config/SecurityConfig.java) - Spring Security 配置

配置 Spring Security 的行为,包括认证策略和过滤器链。

核心配置:

配置项 说明
CSRF 禁用 因为是前后端分离 API 项目
Session STATELESS 无状态,不创建 Session
认证端点 /api/v1/auth/** 公开,无需认证
其他端点 authenticated() 需要登录认证
密码加密 BCrypt 单向哈希加密
java 复制代码
.authorizeHttpRequests(auth -> auth
    .requestMatchers("/api/v1/auth/**").permitAll()  // 登录接口公开
    .anyRequest().authenticated()                     // 其他接口需要认证
)

5. [AuthController.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/controller/AuthController.java) - 认证控制器

处理认证相关的 HTTP 请求。

接口列表:

方法 路径 说明
POST /api/v1/auth/login 用户登录
GET /api/v1/auth/verify 验证 Token

登录请求格式:

json 复制代码
{
  "username": "admin",
  "password": "admin123"
}

登录响应格式:

json 复制代码
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiJ9...",
    "expiresIn": 86400
  },
  "message": "登录成功"
}

6. [AdminUser.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/entity/AdminUser.java) - 管理员用户实体

对应数据库 admin_user 表的实体类,使用 MyBatis-Plus 注解。

字段说明:

字段 类型 说明
id Long 主键,自增
username String 用户名,唯一
password String BCrypt 加密后的密码
nickname String 昵称
avatar String 头像 URL
status Integer 状态:0-禁用,1-正常
createTime LocalDateTime 创建时间
updateTime LocalDateTime 更新时间

注解说明:

  • @TableName("admin_user") - 映射表名
  • @TableId(type = IdType.AUTO) - 主键自增
  • @TableField(fill = ...) - 自动填充时间字段

7. [AdminUserMapper.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/mapper/AdminUserMapper.java) - 用户 Mapper

MyBatis-Plus 的 Mapper 接口,继承 BaseMapper<AdminUser>

无需编写 SQL,MyBatis-Plus 自动提供:

  • selectById(id) - 根据 ID 查询
  • selectOne(queryWrapper) - 条件查询
  • insert(entity) - 插入
  • updateById(entity) - 更新
  • deleteById(id) - 删除

8. [AuthService.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/service/AuthService.java) - 认证服务

处理登录和 Token 验证的业务逻辑。

核心方法:

方法 职责
login(username, password) 验证用户名密码,生成 Token
verify(token) 验证 Token,返回用户信息

登录流程:

复制代码
1. 根据用户名查询用户
2. 检查用户是否存在
3. 检查账号是否被禁用 (status == 0)
4. 验证密码 (BCrypt 匹配)
5. 生成 JWT Token
6. 返回 token 和过期时间

9. [JwtUtil.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/util/JwtUtil.java) - JWT 工具类

封装 JWT Token 的生成和解析操作。

核心方法:

方法 职责
generateToken(userId, username) 生成 Token
validateToken(token) 验证 Token 有效性
parseToken(token) 解析 Token 内容
getUserIdFromToken(token) 获取用户 ID
getUsernameFromToken(token) 获取用户名

Token 包含信息:

  • subject - 用户 ID
  • claim.username - 用户名
  • issuedAt - 签发时间
  • expiration - 过期时间

10. [GlobalExceptionHandler.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/exception/GlobalExceptionHandler.java) - 全局异常处理

使用 @RestControllerAdvice 统一处理所有异常。

处理的异常:

异常类型 HTTP 状态码 响应消息
RuntimeException 400 Bad Request 异常消息
Exception 500 Internal Server Error "服务器内部错误"

响应格式:

json 复制代码
{
  "success": false,
  "message": "错误信息"



}

11. [application.yml](file:///d:/0Document/project/Blog/backend/src/main/resources/application.yml) - 应用配置

Spring Boot 配置文件。

主要配置项:

配置项 说明
server.port 8080 服务端口
datasource.url jdbc:mysql://localhost:3306/blog 数据库连接
datasource.username root 数据库用户名
datasource.password 123456 数据库密码
jwt.secret blog-jwt-secret-key-... JWT 密钥
jwt.expiration 86400000 Token 有效期(24小时)

MyBatis-Plus 配置:

  • map-underscore-to-camel-case: true - 下划线转驼峰
  • logic-delete-field: isDeleted - 逻辑删除字段

12. [schema.sql](file:///d:/0Document/project/Blog/backend/src/main/resources/schema.sql) - 数据库脚本

初始化数据库表结构。

创建的表:

表名 说明
admin_user 管理员用户表

初始化管理员账号:

  • 用户名:admin
  • 密码:admin123(BCrypt 加密)

🔐 认证流程图

复制代码
┌─────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   前端      │     │  AuthController  │     │   AuthService   │
└──────┬──────┘     └────────┬────────┘     └────────┬────────┘
       │                     │                       │
       │  POST /login        │                       │
       │───────────────────►│                       │
       │                     │   login()            │
       │                     │─────────────────────►│
       │                     │                       │
       │                     │    返回 Token         │
       │◄─────────────────────│◄──────────────────────│
       │                     │                       │
       │  后续请求 + Token    │                       │
       │───────────────────►│                       │
       │                     │  JwtAuthenticationFilter │
       │                     │◄───────────────────────│
       │                     │  验证 Token           │
       │                     │──────────────────────►│
       │                     │   放行请求            │
       │                     │──────────────────────►│

📌 总结

这是一个典型的 Spring Boot + JWT 认证 脚手架项目,结构清晰,使用了:

  • MyBatis-Plus 简化数据库操作
  • Spring Security + JWT 实现无状态认证
  • BCrypt 加密密码
  • 全局异常处理 统一错误响应

适合作为博客系统或其他 Web 应用的后端基础。

JwtAuthenticationFilter 工作原理详解

1. 核心继承关系

java 复制代码
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    // ...
}
类/注解 作用
OncePerRequestFilter Spring 提供的抽象类,确保每个请求只执行一次过滤
@Component 注册为 Spring Bean,自动被 Spring 管理
@RequiredArgsConstructor Lombok 自动注入 JwtUtil 依赖

2. 配置到 Security 过滤链

在 [SecurityConfig.java](file:///d:/0Document/project/Blog/backend/src/main/java/com/blog/config/SecurityConfig.java#L35) 中:

java 复制代码
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        // ...
        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    
    return http.build();
}

这行代码的作用是:将自定义过滤器添加到 Spring Security 过滤链中


3. 过滤链顺序

复制代码
请求进入顺序:
┌────────────────────────────────────────────────────────────────┐
│  1. FilterChainProxy                                           │
│     │                                                          │
│     ▼                                                          │
│  2. JwtAuthenticationFilter  ◄── 我们自定义的 Filter           │
│     │                                                          │
│     ▼                                                          │
│  3. UsernamePasswordAuthenticationFilter (Spring Security)    │
│     │                                                          │
│     ▼                                                          │
│     ... 其他 Security Filters ...                              │
│     │                                                          │
│     ▼                                                          │
│  4. DispatcherServlet (Controller)                            │
└────────────────────────────────────────────────────────────────┘

addFilterBefore() 的意思是:在某个过滤器之前执行

所以执行顺序是:JwtAuthenticationFilterUsernamePasswordAuthenticationFilter


4. 核心方法解析

java 复制代码
@Override
protected void doFilterInternal(HttpServletRequest request, 
                                HttpServletResponse response, 
                                FilterChain filterChain)
        throws ServletException, IOException {

    // 步骤 1: 获取请求头
    String authHeader = request.getHeader("Authorization");

    // 步骤 2: 判断是否包含 Bearer Token
    if (authHeader != null && authHeader.startsWith("Bearer ")) {
        
        // 提取 Token (去掉 "Bearer " 前缀)
        String token = authHeader.substring(7);

        // 步骤 3: 验证 Token
        if (jwtUtil.validateToken(token)) {
            
            // 步骤 4: 解析用户信息
            Long userId = jwtUtil.getUserIdFromToken(token);
            String username = jwtUtil.getUsernameFromToken(token);

            // 步骤 5: 存入 Request 供后续使用
            request.setAttribute("userId", userId);
            request.setAttribute("username", username);
        }
    }

    // 步骤 6: 放行请求
    filterChain.doFilter(request, response);
}

5. 完整工作流程图

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         客户端请求                               │
│                GET /api/v1/articles                             │
│                Header: Authorization: Bearer xxx.yyy.zzz       │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                   JwtAuthenticationFilter                        │
│                                                                  │
│  1. 获取 Authorization Header                                    │
│     "Bearer eyJhbGciOiJIUzI1NiJ9..."                            │
│                              │                                   │
│                              ▼                                   │
│  2. 提取 Token                                                   │
│     "eyJhbGciOiJIUzI1NiJ9..."                                   │
│                              │                                   │
│                              ▼                                   │
│  3. jwtUtil.validateToken(token)                               │
│     ├── Token 格式正确?                                         │
│     ├── Token 未过期?                                           │
│     └── 签名验证通过?                                           │
│                              │                                   │
│              ┌─────────────┴─────────────┐                      │
│              │ 验证失败                   │ 验证成功              │
│              ▼                           ▼                      │
│     不解析用户信息              4. 解析用户信息                  │
│     直接放行                     userId = 1                     │
│                                  username = "admin"             │
│                                         │                       │
│                                         ▼                       │
│                              5. 存入 request                     │
│     request.setAttribute("userId", 1);                         │
│     request.setAttribute("username", "admin");                │
│                                         │                       │
│                                         ▼                       │
│                              6. filterChain.doFilter() 放行      │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│              后续 Filter (如 Security Filter)                     │
│              检查 request.getAttribute("userId")                 │
│              判断用户是否已认证                                   │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                         Controller                               │
│              可以通过 request.getAttribute("userId")            │
│              获取当前登录用户 ID                                  │
└─────────────────────────────────────────────────────────────────┘

6. Token 无效时会发生什么?

java 复制代码
if (jwtUtil.validateToken(token)) {
    // Token 有效:解析并存储用户信息
    request.setAttribute("userId", userId);
    request.setAttribute("username", username);
}
// 注意:这里没有 else!
// Token 无效时,不会抛出异常,只是**不存储用户信息**
// 请求会继续放行,到达 Controller

关键点: Token 无效时不会阻止请求,而是让请求继续到达 Controller。此时 Controller 可以选择:

  • 允许匿名访问的接口 → 正常处理
  • 需要登录的接口 → 被 Spring Security 拦截(因为没有认证信息)

7. 后续如何使用用户信息?

在 Controller 或 Service 中:

java 复制代码
@RestController
@RequestMapping("/api/v1/articles")
public class ArticleController {

    @GetMapping
    public ResponseEntity<List<Article>> getArticles(HttpServletRequest request) {
        
        // 从 request 中获取之前存入的用户信息
        Long userId = (Long) request.getAttribute("userId");
        String username = (String) request.getAttribute("username");
        
        if (userId != null) {
            // 用户已登录
            System.out.println("当前用户: " + username);
        }
        
        // 业务逻辑...
    }
}

8. 总结

步骤 代码 说明
1 request.getHeader("Authorization") 获取请求头
2 authHeader.startsWith("Bearer ") 判断是否为 JWT Token
3 jwtUtil.validateToken(token) 验证 Token 签名和有效期
4 jwtUtil.getUserIdFromToken(token) 解析用户 ID
5 request.setAttribute() 存入请求,供后续使用
6 filterChain.doFilter() 必须调用,否则请求会卡住

这个 Filter 的设计非常巧妙:验证与业务分离,只负责解析和验证 Token,不影响正常业务流程。

GlobalExceptionHandler 工作原理详解

1. 核心注解

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

这两个注解的作用:

注解 作用
@RestControllerAdvice = @ControllerAdvice + @ResponseBody - 拦截所有 @RestController 的异常 - 自动将返回值转为 JSON
@ControllerAdvice Spring 提供的全局异常处理器 增强器 - 作用于所有 Controller

2. 工作流程

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        HTTP 请求                                │
└──────────────────────────┬──────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Controller 处理请求                         │
│                    (可能抛出异常)                                │
└──────────────────────────┬──────────────────────────────────────┘
                           │
            ┌──────────────┴──────────────┐
            │ 抛出异常                   │ 正常返回
            ▼                           ▼
┌───────────────────────────────────────────────────────────────┐
│           Spring MVC 异常处理机制                              │
│                                                           │
│   ┌─────────────────────────────────────────────────┐      │
│   │   @RestControllerAdvice 拦截到异常              │      │
│   │                                                 │      │
│   │   @ExceptionHandler(RuntimeException.class)   │─────┼──► 返回 400
│   │   @ExceptionHandler(Exception.class)          │─────┼──► 返回 500
│   │                                                 │      │
│   └─────────────────────────────────────────────────┘      │
└───────────────────────────┬───────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│                     响应 JSON 给前端                            │
└─────────────────────────────────────────────────────────────────┘

3. 异常匹配规则

@ExceptionHandler 的匹配是精确匹配

java 复制代码
@ExceptionHandler(RuntimeException.class)  // 只处理 RuntimeException 及其子类
public ResponseEntity<Map<String, Object>> handleRuntimeException(RuntimeException e) {
    // ...
}

@ExceptionHandler(Exception.class)  // 处理所有未匹配到的异常(兜底)
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
    // ...
}

匹配优先级:

  1. 先查找精确匹配的异常类型
  2. 如果没有,向父类查找(如 RuntimeException 的父类是 Exception)
  3. 最后兜底到 Exception.class

4. 实际例子

场景:用户登录时输入错误密码

java 复制代码
// AuthService.java 中
if (!passwordEncoder.matches(password, user.getPassword())) {
    throw new RuntimeException("密码错误");  // 抛出异常
}

处理流程:

复制代码
1. Controller 调用 authService.login()
2. Service 抛出 RuntimeException("密码错误")
3. Spring 自动捕获异常
4. @RestControllerAdvice 匹配到 RuntimeException 处理方法
5. 返回 400 状态码 + JSON 响应

前端收到的响应:

json 复制代码
HTTP/1.1 400 Bad Request

{
  "success": false,
  "message": "密码错误"
}

5. 源码追踪

@RestControllerAdvice 的位置

复制代码
Spring MVC 处理流程:

DispatcherServlet.doDispatch()
    │
    ▼
HandlerExceptionResolver 异常解析器链
    │
    ├── 1. @ExceptionHandler 方法匹配
    │
    ▼
返回 ModelAndView 或直接写入响应体

Spring MVC 内部会扫描所有带 @ExceptionHandler 的方法,当 Controller 抛出异常时,自动找到最匹配的处理方法。


6. 扩展:添加更多异常处理

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> handleValidationException(
            MethodArgumentNotValidException e) {
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", "参数校验失败");
        response.put("errors", e.getBindingResult().getFieldErrors());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    // 处理 404 异常
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<Map<String, Object>> handleNotFound(
            NoHandlerFoundException e) {
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", "资源不存在");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }

    // 处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Map<String, Object>> handleBusinessException(
            BusinessException e) {
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", e.getMessage());
        response.put("code", e.getCode());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }
}

SecurityConfig.java 工作原理详解

1. 核心注解

java 复制代码
@Configuration                  // 声明这是一个配置类
@EnableWebSecurity              // 启用 Spring Security
@RequiredArgsConstructor       // Lombok - 自动注入依赖
public class SecurityConfig {
注解 作用
@Configuration Spring 配置文件,等价于 XML 配置
@EnableWebSecurity 启用 Spring Security 自动配置
@RequiredArgsConstructor 生成构造函数,自动注入 JwtAuthenticationFilter

2. 核心配置详解

2.1 密码加密器

java 复制代码
@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
  • 提供 BCrypt 密码加密/验证功能
  • 登录时用来比对用户输入的密码和数据库中的加密密码

2.2 安全过滤链(核心)

java 复制代码
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        // 1. 禁用 CSRF(前后端分离不需要)
        .csrf(AbstractHttpConfigurer::disable)
        
        // 2. 无状态会话(JWT 认证不需要 Session)
        .sessionManagement(session -> 
            session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        )
        
        // 3. 请求授权配置
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/v1/auth/**").permitAll()  // 公开接口
            .anyRequest().authenticated()                     // 其他需认证
        )
        
        // 4. 添加 JWT 过滤器
        .addFilterBefore(jwtAuthenticationFilter, 
            UsernamePasswordAuthenticationFilter.class);

    return http.build();
}

3. 配置项逐个解析

3.1 CSRF 禁用

java 复制代码
.csrf(AbstractHttpConfigurer::disable)
项目 说明
什么是 CSRF 跨站请求伪造攻击
为什么禁用 前后端分离项目使用 JWT,不需要 CSRF Token
风险 无风险,JWT 本身已足够安全

3.2 会话策略

java 复制代码
.sessionManagement(session -> 
    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
策略 说明
STATELESS 无状态 - 不创建 Session - 不使用 Cookie - 每次请求都带 Token
复制代码
对比:
┌─────────────────────────────────────────────────────────┐
│ 有状态 (传统 Session)                                    │
│  登录 → 服务器创建 Session → 返回 SessionID → Cookie    │
│  后续请求 → 带 Cookie → 服务器验证 Session              │
├─────────────────────────────────────────────────────────┤
│ 无状态 (JWT)                                             │
│  登录 → 服务器生成 Token → 返回给前端                     │
│  后续请求 → Header 带 Token → 服务器验证 Token           │
│  ★ 服务器不存储任何会话信息                               │
└─────────────────────────────────────────────────────────┘

3.3 请求授权

java 复制代码
.authorizeHttpRequests(auth -> auth
    .requestMatchers("/api/v1/auth/**").permitAll()   // 公开
    .anyRequest().authenticated()                     // 其他需登录
)
规则 路径 访问权限
permitAll() /api/v1/auth/** 所有人可访问
authenticated() 其他所有路径 需要登录认证
复制代码
请求流程:
┌──────────────────────────────────────────────────────┐
│                                                      │
│  请求 /api/v1/auth/login                             │
│         │                                            │
│         ▼                                            │
│  .requestMatchers("/api/v1/auth/**").permitAll()   │
│         │                                            │
│         ▼ 匹配到!直接放行                            │
│  Controller 处理                                    │
│                                                      │
├──────────────────────────────────────────────────────┤
│                                                      │
│  请求 /api/v1/articles                               │
│         │                                            │
│         ▼                                            │
│  .requestMatchers("/api/v1/auth/**").permitAll()   ✗ 不匹配
│         │                                            │
│         ▼                                            │
│  .anyRequest().authenticated()                      │
│         │                                            │
│         ▼ 需要认证!                                  │
│  检查是否有有效 Token                                 │
│    ├── 有 → 放行                                     │
│    └── 无 → 返回 401                                 │
│                                                      │
└──────────────────────────────────────────────────────┘

3.4 添加 JWT 过滤器

java 复制代码
.addFilterBefore(jwtAuthenticationFilter, 
    UsernamePasswordAuthenticationFilter.class)

作用:将自定义 JWT 过滤器插入到 Spring Security 过滤链中

复制代码
过滤链顺序(从左到右执行):

┌─────────────────────────────────────────────────────────┐
│  1. JwtAuthenticationFilter  ◄── 我们自定义的 Filter    │
│     (提取并验证 Token,存入用户信息)                     │
├─────────────────────────────────────────────────────────┤
│  2. UsernamePasswordAuthenticationFilter                │
│     (Spring Security 默认的表单登录过滤器)                │
│     - 如果已认证,跳过                                   │
│     - 如果未认证且是登录请求,尝试认证                    │
├─────────────────────────────────────────────────────────┤
│  3. 其他 Security Filters...                           │
│     (授权检查、异常处理等)                               │
├─────────────────────────────────────────────────────────┤
│  4. DispatcherServlet                                 │
│     (到达 Controller)                                  │
└─────────────────────────────────────────────────────────┘

4. 完整请求处理流程

复制代码
客户端请求
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│              Spring Security 过滤链                       │
│                                                          │
│  1. JwtAuthenticationFilter                            │
│     ├── 获取 Authorization Header                        │
│     ├── 提取并验证 JWT Token                             │
│     ├── 解析 userId/username                            │
│     └── 存入 request.setAttribute()                     │
│                                                          │
│  2. Spring Security 内置过滤器                          │
│     └── 检查是否已认证 (isAuthenticated)                │
│                                                          │
│  3. AuthorizationFilter                                │
│     └── 检查路径权限                                     │
│                                                          │
└────────────────────────┬────────────────────────────────┘
                         │
         ┌───────────────┴───────────────┐
         │                               │
      验证通过                         验证失败
         │                               │
         ▼                               ▼
┌─────────────────┐             ┌─────────────────┐
│   放行请求      │             │  返回 401       │
│  到 Controller  │             │  未授权错误     │
└─────────────────┘             └─────────────────┘

5. 配置类比理解

可以把 SecurityConfig 理解为一份安检流程表

复制代码
安检流程:

┌─────────────────────────────────────────────┐
│  1. 开放入口 vs 封闭入口                      │
│     - 登录口 (permitAll) → 任何人可进         │
│     - 其他入口 (authenticated) → 凭证入场    │
│                                             │
│  2. 凭证类型                                 │
│     - 传统:会员卡 (Session)                 │
│     - 现代:刷脸/刷身份证 (JWT Token)         │
│                                             │
│  3. 验证规则                                 │
│     - 检查证件有效性                         │
│     - 检查是否有权限进入                     │
│                                             │
│  4. 异常处理                                 │
│     - 证件无效 → 驱逐出境 (401)              │
│     - 证件过期 → 提醒续期 (提示登录)          │
└─────────────────────────────────────────────┘

6. 总结

配置项 作用
@Configuration 注册为配置类
@EnableWebSecurity 启用安全功能
BCryptPasswordEncoder 密码加密/验证
csrf().disable() 禁用 CSRF(前后端分离)
STATELESS 无状态会话(JWT)
permitAll() 公开接口
authenticated() 需要认证
addFilterBefore() 添加 JWT 过滤器

这套配置是 JWT + Spring Security 的标准组合拳,简洁高效!

7. 总结

特性 说明
作用范围 所有 @RestController
生效条件 Controller 抛出异常
匹配规则 精确匹配 → 父类匹配 → 兜底匹配
返回值 自动转为 JSON(因为用了 @RestControllerAdvice
状态码 @ExceptionHandler 中指定的 ResponseEntity.status() 决定

这样前端只需要统一处理 success: false 的响应即可,无需在每个 Controller 中单独处理异常。

相关推荐
Mr_Xuhhh2 小时前
算法刷题笔记:从滑动窗口到哈夫曼编码,我的算法进阶之路
开发语言·算法
七夜zippoe2 小时前
Java技术未来展望:GraalVM、Quarkus、Helidon等新趋势探讨
java·开发语言·python·quarkus·graaivm·helidon
枫叶落雨2222 小时前
ClassPathXmlApplicationContext
java·开发语言
草莓熊Lotso2 小时前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·linux·运维·服务器·数据库·c++·mysql
gelald2 小时前
Spring Boot - 自动配置原理
java·spring boot·后端
hssfscv2 小时前
软件设计师下午题六——Java的各种设计模式
java·算法·设计模式
希望永不加班2 小时前
SpringBoot 集成测试:@SpringBootTest 与 MockMvc
java·spring boot·后端·log4j·集成测试
enAn_2 小时前
对照片和视频文件名,程序追加日期,直观看
java·maven
十五年专注C++开发2 小时前
Oat++: 一个轻量级、高性能、零依赖的 C++ Web 框架
开发语言·c++·web服务·oatpp