package com.crm.auth.config; import com.crm.auth.security.JwtAuthenticationFilter; import com.crm.auth.security.SecurityExceptionHandlers; import lombok.RequiredArgsConstructor; 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.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * Spring Security 配置:无状态 JWT 模式 *
依赖了 crm-auth 的业务模块自动获得本配置(登录接口 + token 校验 + 401/403 JSON 返回)
*/ @Configuration @EnableWebSecurity @EnableMethodSecurity @RequiredArgsConstructor public class SecurityConfig { /** * 默认放行路径;业务模块如需追加,配置 crm.auth.ignore-urls */ private static final String[] DEFAULT_IGNORE_URLS = { // 登录接口 "/api/auth/login/**", // 接口文档 "/doc.html", "/webjars/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**", // 其他 "/favicon.ico", "/error", }; private final JwtAuthenticationFilter jwtAuthenticationFilter; private final SecurityExceptionHandlers securityExceptionHandlers; private final AuthProperties authProperties; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // JWT 无状态,关闭 csrf 和 session .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> { auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .requestMatchers(DEFAULT_IGNORE_URLS).permitAll(); // 业务模块通过 crm.auth.ignore-urls 追加的放行路径 if (!authProperties.getIgnoreUrls().isEmpty()) { auth.requestMatchers(authProperties.getIgnoreUrls().toArray(String[]::new)).permitAll(); } auth.anyRequest().authenticated(); }) .exceptionHandling(handler -> handler .authenticationEntryPoint(securityExceptionHandlers) .accessDeniedHandler(securityExceptionHandlers)) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } }