Angular+Spring Boot跨域权限问题:ADMIN接口CORS报错解决
问题描述
使用Angular(localhost:4200)作为前端,Spring Boot(localhost:8080)作为后端,控制器路径为/api/v1/admin。以管理员身份发送GET请求获取数据库所有用户时,出现No 'Access-Control-Allow-Origin' header is present on the requested resource错误。排查发现,当SecurityFilterChain中配置.requestMatchers("/api/v1/admin/**").hasAuthority("ADMIN")时触发错误,改为.requestMatchers("/api/v1/admin/**").permitAll()则正常,但需求是限制该路径仅ADMIN角色可访问,需解决此问题。
补充代码
SecurityConfig类
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthFilter jwtAuthFilter; private final AuthenticationProvider authenticationProvider; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity .cors(cors -> cors.disable()) .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/**").permitAll() .requestMatchers("/api/v1/admin/**").hasAuthority("ADMIN") //.requestMatchers("/api/v1/admin/**").permitAll() .requestMatchers("/api/v1/demo-controller/admin").hasAuthority("ADMIN") .requestMatchers("/api/v1/demo-controller/user").hasAuthority("USER") .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); } @Bean CorsConfigurationSource corsConfigurationSource() { List<String> allowedOriginUrls = new ArrayList<>(); allowedOriginUrls.add("localhost:8080"); allowedOriginUrls.add("localhost:4200"); CorsConfiguration corsConfiguration=new CorsConfiguration(); corsConfiguration.setAllowedOrigins(allowedOriginUrls); corsConfiguration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE")); corsConfiguration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Auth-Token")); corsConfiguration.addExposedHeader("*"); UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfiguration); return source; } }
AdminController类
@RestController @RequestMapping("/api/v1/admin") @RequiredArgsConstructor public class AdminController { private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final UserService userService; @GetMapping("/users") public ResponseEntity<List<UserDto>> findAllUsers() { LOGGER.info("GET /api/v1/auth/users"); try { return userService.findAllUsers(); } catch (Exception e) { return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); } } @GetMapping("/users/{email}") public ResponseEntity<UserDto> findUserByEmail(@PathVariable String email) { LOGGER.info("GET /api/v1/admin/users/{}", email); try { return userService.findUserByEmail(email); } catch (Exception e) { return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); } } }
解决方案
问题根源在于之前在SecurityFilterChain中禁用了CORS(.cors(cors -> cors.disable())),导致自定义的CORS配置未生效。当路径需要权限验证时,浏览器发送的预检OPTIONS请求会被Spring Security拦截,返回的响应缺少CORS相关头,从而触发跨域错误。
只需在HttpSecurity中应用自定义的CORS配置而非禁用它,同时完善CORS配置细节(如添加协议前缀、允许凭证等)即可解决问题。修改后的SecurityConfig类代码如下:
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthFilter jwtAuthFilter; private final AuthenticationProvider authenticationProvider; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity .csrf(csrf -> csrf.disable()) .cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/**").permitAll() .requestMatchers("/api/v1/admin/**").hasAuthority("ADMIN") //.requestMatchers("/api/v1/admin/**").permitAll() .requestMatchers("/api/v1/demo-controller/admin").hasAuthority("ADMIN") .requestMatchers("/api/v1/demo-controller/user").hasAuthority("USER") .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfiguration=new CorsConfiguration(); corsConfiguration.addAllowedOrigin("http://localhost:8080"); corsConfiguration.addAllowedOrigin("http://localhost:4200"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfiguration); return source; } }
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

