SimpleCorsFilter 类未被使用。此外,Auth Controller 和 Admin Contoller 中的方法也没有被使用。 SpringApplication 似乎没有扫描它们。因此,每当前端请求时,它都会抛出 403 Forbidden。
这里是 SIMPLECORSFILTER 类的代码
package com.mcaproject.configuration;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class SimpleCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
// Allow requests from all origins
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
// For OPTIONS requests, just return OK status
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
// For other requests, continue with the filter chain
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
WEB 安全配置代码
package com.mcaproject.configuration;
import com.mcaproject.enums.UserRole;
import com.mcaproject.services.jwt.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
@Configuration
public class WebSecurityConfiguration {
@Autowired
private final JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private final UserService userService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(request ->
request.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasAnyAuthority(UserRole.ADMIN.name())
.requestMatchers("/api/customer/**").hasAnyAuthority(UserRole.CUSTOMER.name()).
anyRequest().authenticated()).sessionManagement(manager ->
manager.sessionCreationPolicy(STATELESS)).
authenticationProvider(authenticationProvider()).
addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userService.userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
管理控制器代码
package com.mcaproject.controller;
import com.mcaproject.dto.CarDto;
import com.mcaproject.services.admin.AdminService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.Console;
import java.io.IOException;
@RestController
@RequestMapping("/api/admin")
@RequiredArgsConstructor
public class AdminController {
private final AdminService adminService;
@PostMapping("/car")
public ResponseEntity<?> postCar(@ModelAttribute CarDto carDto) {
try {
boolean success = adminService.postCar(carDto);
if (success) {
return ResponseEntity.status(HttpStatus.CREATED).body("Car posted successfully");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Failed to post car");
}
} catch (IOException e) {
System.out.print(e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error occurred while posting car: " + e.getMessage());
}
}
}
身份验证控制器代码
package com.mcaproject.controller;
import com.mcaproject.dto.AuthenticationRequest;
import com.mcaproject.dto.AuthenticationResponse;
import com.mcaproject.dto.SignupRequest;
import com.mcaproject.dto.UserDto;
import com.mcaproject.entity.User;
import com.mcaproject.repository.UserRepository;
import com.mcaproject.services.auth.AuthService;
import com.mcaproject.services.jwt.UserService;
import com.mcaproject.utils.JWTUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Optional;
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
private final AuthenticationManager authenticationManager;
private final UserService userService;
private final JWTUtil jwtUtil;
private final UserRepository userRepository;
@PostMapping("/signup")
public ResponseEntity<?> signupCustomer(@RequestBody SignupRequest signupRequest) {
if(authService.hasCustomerWithEmail(signupRequest.getEmail()))
return new ResponseEntity<>("Customer already exists with this email", HttpStatus.NOT_ACCEPTABLE);
UserDto createdCustomerDto= authService.createCustomer(signupRequest);
if(createdCustomerDto == null)
return new ResponseEntity<>("Customer not created, try again", HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(createdCustomerDto, HttpStatus.CREATED);
}
@PostMapping("/login")
public AuthenticationResponse createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws
BadCredentialsException,
DisabledException,
UsernameNotFoundException {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getEmail(), authenticationRequest.getPassword()));
}
catch (BadCredentialsException e) {
throw new BadCredentialsException("Incorrect username or password");
}
final UserDetails userDetails = userService.userDetailsService().loadUserByUsername(authenticationRequest.getEmail());
Optional<User> optionalUser = userRepository.findFirstByEmail(userDetails.getUsername());
final String jwt = jwtUtil.generateToken(userDetails);
final String refreshToken = jwtUtil.generateRefreshToken(new HashMap<>(), userDetails);
AuthenticationResponse authenticationResponse = new AuthenticationResponse();
if(optionalUser.isPresent()) {
authenticationResponse.setJwt(jwt);
authenticationResponse.setRefreshToken(refreshToken);
authenticationResponse.setUserId(optionalUser.get().getId());
authenticationResponse.setUserRole(optionalUser.get().getUserRole());
}
return authenticationResponse;
}
}
用
@WebFilter(urlPatterns = "/*")
注释您的过滤器。确保您的 OPTIONS
电话能够接通。
但是您不需要
Filter
来启用 CORS,这不是标准做法。如果您使用的是 Spring Boot,您可以简单地配置全局 WebMvcConfigurer
bean,如 Spring 指南中提到的 :
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("http://localhost:9000"); // list of allowed origins
}
};
}
如果您没有使用 Spring Boot,那么您可以使用
CorsConfigurationSource
bean,如 spring 文档中提到的:
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}