Merge remote-tracking branch 'origin/master'

This commit is contained in:
LYC 2025-04-29 23:06:42 +08:00
commit f92e5bead8
2 changed files with 51 additions and 6 deletions

View File

@ -0,0 +1,19 @@
package com.waterquality.projectmanagement.config;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import java.io.IOException;
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回 401 状态码
response.setContentType("application/json");
response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"You are not authenticated.\"}");
}
}

View File

@ -2,6 +2,8 @@ package com.waterquality.projectmanagement.config;
import com.waterquality.projectmanagement.repository.EmployeeRepository; import com.waterquality.projectmanagement.repository.EmployeeRepository;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.catalina.filters.CorsFilter; import org.apache.catalina.filters.CorsFilter;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -19,6 +21,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
@ -37,22 +40,45 @@ public class SecurityConfig {
private final EmployeeRepository employeeRepository; private final EmployeeRepository employeeRepository;
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
// @Bean
// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// http
// .csrf(csrf -> csrf.disable())
// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 配置 CORS
// .authorizeHttpRequests(authz -> authz
// .requestMatchers("/api/auth/**").permitAll()
// .requestMatchers("/static/**","/assets/**").permitAll()
// .requestMatchers("/", "/login","/index.html","/favicon.svg").permitAll() // 确保允许访问根路径和登录路径
// .anyRequest().authenticated())
// .authenticationProvider(authenticationProvider())
// .addFilterBefore((Filter) new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
//
// return http.build();
// }
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http http
.csrf(csrf -> csrf.disable()) .csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // 配置 CORS .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 配置 CORS
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authz -> authz .authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/**").permitAll() .requestMatchers("/api/auth/**").permitAll() // 允许认证相关接口无需鉴权
.requestMatchers("/static/**","/assets/**").permitAll() .requestMatchers("/api/**").authenticated() // 只有 /api/** 下的路由需要鉴权
.requestMatchers("/", "/login","/index.html","/favicon.svg").permitAll() // 确保允许访问根路径和登录路径 .requestMatchers("/static/**", "/css/**", "/js/**", "/assets/**", "/favicon.ico").permitAll() // 显式放通静态资源
.anyRequest().authenticated()) .requestMatchers("/", "/index.html").permitAll() // 放通 SPA 的入口页面
.anyRequest().permitAll()) // 其他所有请求都无需鉴权
.exceptionHandling(exception -> exception
.authenticationEntryPoint(new Http401UnauthorizedEntryPoint()))
.authenticationProvider(authenticationProvider()) .authenticationProvider(authenticationProvider())
.addFilterBefore((Filter) new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }
@Bean @Bean
public CorsConfigurationSource corsConfigurationSource() { public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();