package com.mikufufu.config; import com.mikufufu.modules.auth.security.filter.IllegalRequestFilter; import com.mikufufu.modules.auth.security.filter.TokenFilter; import com.mikufufu.modules.auth.security.handler.AuthorizationManagerImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authorization.AuthorizationManager; 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.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Arrays; import java.util.Collections; import java.util.stream.Stream; /** * Spring Security配置类 * */ @Slf4j @Configuration // 表示这是一个配置类 @EnableWebSecurity // 启用Spring Web安全功能 @EnableMethodSecurity public class SecurityConfig { /** * 认证失败处理类:用于处理认证失败的情况。 */ @Autowired private AuthenticationEntryPoint authenticationEntryPoint; /** * 权限拒绝处理类:用于处理没有权限访问的情况。 */ @Autowired private AccessDeniedHandler accessDeniedHandler; // 解决循环依赖的问题 @Bean public AuthorizationManager authorizationManager(){ return new AuthorizationManagerImpl(); } /** * 获取匿名访问的权限列表。 * 匿名权限即不需要用户登录即可访问的资源路径。 * * @return 返回一个包含所有匿名权限路径的列表。 */ private String[] anonymousGet(){ // 初始化匿名权限路径列表,包括默认权限、Swagger文档权限 String[] defaultPermission = {"/cache/**","/logout"}; String[] swaggerPermission = {"/doc.html","/swagger-resources/**","/webjars/**","/v3/api-docs/**","/swagger-ui/**"}; // 合并权限列表,去除重复项 return Stream.of(defaultPermission, swaggerPermission) .flatMap(Arrays::stream).distinct() .toArray(String[]::new); } /** * 静态资源路径 * 解决 ** 路径无法匹配的问题 * @return AntPathRequestMatcher[] */ private AntPathRequestMatcher[] staticResources(){ String[] staticPath = {"/","/*.html","/**/*.html","/**/*.js","/**/*.css","/favicon.ico","/image/**"}; // 创建一个AntPathRequestMatcher数组,用于匹配静态资源路径 AntPathRequestMatcher[] antPathRequestMatchers = new AntPathRequestMatcher[staticPath.length]; // 遍历静态资源路径数组,为每个路径创建一个AntPathRequestMatcher对象 for (int i = 0; i < staticPath.length; i++) { antPathRequestMatchers[i] = new AntPathRequestMatcher(staticPath[i]); } // 返回AntPathRequestMatcher数组 return antPathRequestMatchers; } /** * 配置CORS(跨源资源共享)设置,以允许来自特定源的Web请求访问应用程序。 * 这个方法返回一个CorsConfigurationSource实例,其中包含了对跨域请求的配置。 * @return UrlBasedCorsConfigurationSource 一个基于URL的CORS配置源,用于指定哪些URL路径应用此CORS配置。 */ @Bean public CorsConfigurationSource configurationSource(){ // 创建一个新的CORS配置对象 CorsConfiguration corsConfiguration = new CorsConfiguration(); // 设置允许的所有请求头 corsConfiguration.setAllowedHeaders(Collections.singletonList("*")); // 设置允许的所有请求方法 corsConfiguration.setAllowedMethods(Collections.singletonList("*")); // 设置允许的请求来源,这里指定了两个来源:本地开发环境和一个示例域名 // corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8080","https://www.mikufufu.com")); corsConfiguration.addAllowedOrigin("*"); // 设置预检请求(OPTIONS请求)的缓存时间,单位为秒 corsConfiguration.setMaxAge(3600L); // 创建一个新的URL基于的CORS配置源 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // 将之前配置的CORS配置应用到所有URL路径 source.registerCorsConfiguration("/**",corsConfiguration); // 返回配置源 return source; } /** * 配置安全过滤链 * @param http 用于配置HttpSecurity的bean * @return 返回配置好的SecurityFilterChain * @throws Exception 配置过程中可能抛出的异常 */ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 配置CORS跨域资源共享 .cors(cors -> cors.configurationSource(configurationSource())) // 禁用CSRF保护 .csrf(AbstractHttpConfigurer::disable) // 禁用会话创建 .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 禁用security默认的注销接口,以解决重定向到login页面时,因为没有登录,所以会重定向到登录页面,但是登录页面没有权限,所以会抛出异常。 .logout(AbstractHttpConfigurer::disable) // 配置请求过滤规则 .authorizeHttpRequests(authorize -> authorize // 放行静态资源 .requestMatchers(staticResources()).permitAll() // 允许GET请求和POST请求 .requestMatchers(HttpMethod.GET, anonymousGet()).permitAll() .requestMatchers(HttpMethod.POST, "/login","/admin/login","/register").permitAll() // 使用自定义的权限管理器进行权限检查 .anyRequest().access(authorizationManager()) ) .addFilterBefore(new TokenFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new IllegalRequestFilter(),TokenFilter.class); // 允许iframe访问 http.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)); http.exceptionHandling(exceptionHandling -> exceptionHandling // 认证失败处理 .authenticationEntryPoint(authenticationEntryPoint) // 权限不足处理 .accessDeniedHandler(accessDeniedHandler)); // 构建并返回安全过滤链 return http.build(); } }