package com.learn.config; import com.learn.security.JwtAuthFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * Spring Security 配置(第 1-3 天) * * 核心设计: * 1. 无状态会话(JWT,不依赖 Cookie/Session) * 2. 自定义 JWT 过滤器在 UsernamePasswordAuthenticationFilter 之前执行 * 3. RBAC:ADMIN 可增删改,USER 只能查 * 4. 公开 /api/auth/** 和 Actuator 端点 */ @Configuration @EnableWebSecurity @EnableMethodSecurity // 开启方法级安全注解(第 3 天) public class SecurityConfig { private final JwtAuthFilter jwtAuthFilter; public SecurityConfig(JwtAuthFilter jwtAuthFilter) { this.jwtAuthFilter = jwtAuthFilter; } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) // 前后端分离,禁用 CSRF .sessionManagement(sm -> sm .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态 .authorizeHttpRequests(auth -> auth // 公开接口 .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/actuator/**").permitAll() .requestMatchers("/", "/index.html", "/css/**", "/js/**").permitAll() // 查询:USER 及以上 .requestMatchers(HttpMethod.GET, "/api/students/**").hasAnyRole("ADMIN", "USER") // 增删改:仅 ADMIN(第 3 天 RBAC) .requestMatchers(HttpMethod.POST, "/api/students/**").hasRole("ADMIN") .requestMatchers(HttpMethod.PUT, "/api/students/**").hasRole("ADMIN") .requestMatchers(HttpMethod.DELETE, "/api/students/**").hasRole("ADMIN") // 其他请求需认证 .anyRequest().authenticated() ) // 在用户名密码过滤器之前插入 JWT 过滤器 .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // BCrypt 加密,不可逆 } }