package com.backendsys.modules.common.config.security; import cn.hutool.core.util.ArrayUtil; //import com.backendsys.modules.common.KLingAiConfig.security.filter.AnonymousFilter; import com.backendsys.modules.common.config.security.annotations.AnonymousProperties; import com.backendsys.modules.common.config.security.filter.CaptchaVerficationFilter; import com.backendsys.modules.common.config.security.filter.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.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; @Configuration @EnableWebSecurity @RequiredArgsConstructor // @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) @EnableMethodSecurity(securedEnabled = true) public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; // private final AnonymousFilter anonymousFilter; @Bean public PasswordEncoder getPw() { return new BCryptPasswordEncoder(); } @Bean public CaptchaVerficationFilter CaptchaVerficationFilter() { return new CaptchaVerficationFilter(); } @Value("${MAXIMUM_SESSIONS}") private Integer MAXIMUM_SESSIONS; @Value("#{'${whitelist.static}'.split(',')}") private final String[] STATIC_WHITELIST; @Value("#{'${whitelist.jwt}'.split(',')}") private final String[] JWT_WHITELIST; // 获得配置文件中的白名单变量,注意首尾要去空格 private String[] getWhiteUrls() { String [] result = ArrayUtil.addAll(JWT_WHITELIST, STATIC_WHITELIST); for (int i = 0; i < result.length; i++) { result[i] = result[i].trim(); } return result; } // Spring-Security 更新日志文档 (升级版本是否对语法有影响): // https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/web/server/ServerHttpSecurity.html @Autowired private AnonymousProperties anonymousProperties; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // 在配置文件中的 白名单地址 String[] whiteUrls = getWhiteUrls(); // System.out.println(Arrays.toString(whiteUrls)); // 使用了 @Anonymous 注解的地址 String[] anonymousUrls = anonymousProperties.getUrls(); // System.out.println("(SecurityConfig) anonymousUrls:"); // System.out.println(Arrays.toString(anonymousUrls)); // 路径授权 http // 禁用csrf(防止跨站请求伪造攻击) //.csrf(csrf -> csrf.disable()) .csrf(AbstractHttpConfigurer::disable) // 设置白名单 .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests // .requestMatchers("/api/**").permitAll() // .requestMatchers(whiteUrls).permitAll() // .requestMatchers(anonymousUrls).permitAll() // .anyRequest().authenticated() .anyRequest().permitAll() // 开放所有mvc页面 ) // "/api/auth/login", // 对于其他任何请求,都保护起来 // 禁用缓存 .sessionManagement((sessionManagement) -> sessionManagement .sessionConcurrency((sessionConcurrency) -> sessionConcurrency .maximumSessions(MAXIMUM_SESSIONS) // 限制用户会话并发数量 (防止恶意用户同时使用多个会话进行非法操作) //.expiredUrl("/login?expired") ) .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) // .addFilterBefore(anonymousFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) ; // 使用无状态session,即不使用session缓存数据 // .logout() // .logoutUrl("/api/auth/logout") // .addLogoutHandler(new CustomLogoutHandler()) // .logoutSuccessHandler(((request, response, authentication) -> SecurityContextHolder.clearContext())); // .authorizeHttpRequests( // (requests) -> requests // // 放行路径 (6.0 下,antMatchers 已弃用,使用 requestMatchers 代替) // .requestMatchers("/", "/api/**").permitAll() // // 放行静态资源 (/resources/static/images/p1.jpg) // .requestMatchers("/*.ico", "/images/**").permitAll() // // , // .anyRequest().authenticated() // ) // .formLogin((form) -> // form // // 进入登录跳转页面 // .loginPage("/login") // // // 自定义拦截器 (错误/成功) // .failureHandler(new CustomAuthenticationFailureHandler()) // .successHandler(new CustomAuthenticationSuccessHandler()) // // .permitAll() // ).logout((logout) -> // logout // // 退出登录后跳转页面 // .logoutSuccessUrl("/") // .permitAll() // ); // http.cors(); // 允许跨域 return http.build(); } // 跨域资源配置 //@Bean //public CorsConfigurationSource corsConfigurationSource() { // CorsConfiguration configuration = new CorsConfiguration(); // configuration.setAllowedOrigins(Collections.singletonList("*")); // Arrays.asList("*") // configuration.setAllowedMethods(Collections.singletonList("*")); // // "GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH" // configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token")); // UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // source.registerCorsConfiguration("/**", configuration); // return source; //} }