You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 14:57:12