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

Spring Boot与Angular 4集成时的CORS Origin问题排查

Fixing CORS Origin Error in JWT Auth Between Angular 4 and Spring Boot

Hey there, let's tackle your CORS issue head-on. You're right to suspect the JWTAuthorizationFiler—the way you're handling CORS headers directly in the filter is conflicting with Spring's native CORS processing, especially for preflight OPTIONS requests. Here's a step-by-step solution to get things working:

1. Replace Manual CORS Header Handling with Spring's Official Configuration

Spring has a built-in, robust way to configure CORS that avoids conflicts with security filters. Add this bean to your SecurityConfig class:

import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.cors.CorsConfigurationSource;
import java.util.Arrays;

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    // Replace with your Angular app's actual URL (avoid "*" if using credentials)
    configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList(
        "Origin", "Accept", "X-Requested-With", "Content-Type", 
        "Access-Control-Request-Method", "Access-Control-Request-Headers", 
        "Authorization" // Match your JWT header name
    ));
    // Expose the Authorization header so Angular can access it after login
    configuration.setExposedHeaders(Arrays.asList("Authorization"));
    // Enable this if your Angular app uses withCredentials: true in requests
    configuration.setAllowCredentials(true);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

Then update your configure(HttpSecurity http) method to use this CORS configuration instead of manual headers:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .cors().configurationSource(corsConfigurationSource()) // Add this line
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
            .antMatchers("/login/**", "/register/**", "/paramsApi/**").permitAll()
            .antMatchers(HttpMethod.POST, "/studentResource/**").hasAuthority("ADMIN")
            .antMatchers(HttpMethod.GET, "/studentResource/**").hasAuthority("ADMIN")
            .anyRequest().authenticated()
        .and()
        .addFilter(new JWTAuthenticationFilter(authenticationManager()))
        .addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class); // Fix class name spelling here
}

2. Clean Up the JWT Authorization Filter

Remove all manual CORS header code from your JWTAuthorizationFilter (fixed the class name spelling too) and add error handling for invalid JWTs:

public class JWTAuthorizationFilter extends OncePerRequestFilter {
    @SuppressWarnings("unchecked")
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // Let Spring's CORS config handle headers now
        if (request.getMethod().equals(HttpMethod.OPTIONS.name())) {
            response.setStatus(HttpServletResponse.SC_OK);
            filterChain.doFilter(request, response);
            return;
        }

        String jwt = request.getHeader(SecurityConstants.HEADER_STRING);
        if (jwt == null || !jwt.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            filterChain.doFilter(request, response);
            return;
        }

        try {
            Claims claims = Jwts.parser()
                .setSigningKey(SecurityConstants.SECRET)
                .parseClaimsJws(jwt.replace(SecurityConstants.TOKEN_PREFIX, ""))
                .getBody();

            String username = claims.getSubject();
            ArrayList<Map<String, String>> roles = (ArrayList<Map<String, String>>) claims.get("roles");
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            
            roles.forEach(r -> authorities.add(new SimpleGrantedAuthority(r.get("authority"))));
            
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                username, null, authorities
            );
            SecurityContextHolder.getContext().setAuthentication(authToken);
        } catch (Exception e) {
            // Handle invalid/expired JWTs gracefully
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid or expired JWT token");
            return;
        }

        filterChain.doFilter(request, response);
    }
}

3. Verify Angular Request Configuration

Make sure your Angular login request includes withCredentials: true if you're using cookies or authenticated sessions (match the setAllowCredentials(true) in your Spring config):

this.http.post('/login', yourCredentials, { withCredentials: true })
  .subscribe(response => {
    // Extract and store the JWT from the Authorization header
  });

Why This Works

  • Spring's native CORS configuration properly handles preflight OPTIONS requests, which your manual filter code was partially handling but not consistently.
  • Separating CORS logic from the JWT filter avoids header conflicts and ensures all request types (including preflight) get the correct headers.
  • Adding error handling for invalid JWTs prevents unexpected 500 errors and gives clear feedback to the frontend.

内容的提问来源于stack exchange,提问作者Soufiane Rabii

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:12:44