0
votes

I have Spring boot rest application. Recently I have implemented user authentication using JsonWebToken.

Everything seems to work fine when I test it using postman, but when the rest is called from Angular Application I got errors refering to cors:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.

Here is my code:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private JwtAuthFilter authFilter;

@Autowired
private JwtAuthenticationProvider authenticationProvider;

@Autowired
private JwtAuthenticationEntryPoint authenticationEntryPoint;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    //http.csrf().ignoringAntMatchers("/token");
    http.csrf().disable();

    http.cors().and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/token").permitAll()
            .antMatchers("/rest/**").authenticated()
            .and()
            .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint);

}


@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS","PUT","DELETE"));
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/rest/**", configuration);
    return source;
}


}

JwtAuthFilter:

@Component
public class JwtAuthFilter implements Filter
{

@Override
public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
    HttpServletRequest servletRequest = (HttpServletRequest) request;
    HttpServletResponse response = (HttpServletResponse) servletResponse;

    String authorization = servletRequest.getHeader("Authorization");
    String origin = servletRequest.getHeader("Origin");

    if (authorization != null)
    {
        JwtAuthToken token = new JwtAuthToken(authorization.replaceAll("Bearer ", ""));
        SecurityContextHolder.getContext().setAuthentication(token);
    }

    filterChain.doFilter(servletRequest, response);
}

@Override
public void destroy()
{

}

@Override
public void init(FilterConfig filterConfig) throws ServletException
{

}
}

My login Controller has a mapping "/token", and all other controllers are mapped as "/rest/**" Interesting is that calling a "/token" controller works fine... it returns token and user details. Server respond contains:

but when I call any other controller... for example "/rest/task/all" I got error and there is no access-control-allow-credentials and access-control-allow-origin headers.

when I change

source.registerCorsConfiguration("/rest/**", configuration);

to source.registerCorsConfiguration("/**", configuration);

I got error that I have two values in access-control-allow-origin header http://localhost:4200 and http://localhost:4200

Anyone has any help to offer :D ?

1

1 Answers

0
votes

Its an old question & I am not sure if you found an answer. I can suggest only ways to debug these issues as these issues usually are very local to set up.

1.First - Only Java code is not enough to debug CORS issues. You need to look at Browser Network tabs and see which call failed - OPTIONS call or actual data call. Second , In browser , request & response headers need to be looked at closely for failing request & those need to be listed down esp. these below .

On request side - Origin

On response side - Access-Control-Allow-Credentials , Access-Control-Allow-Headers , Access-Control-Allow-Methods & Access-Control-Allow-Origin

2.

Everything seems to work fine when I test it using postman, but when the rest is called from Angular Application I got errors refering to cors:

This is normal behavior as CORS is a browser security feature and you might not see this issue in any other client. CORS error doesn't mean that your API call doesn't succeeded, it only means that browser is suppressing the response & not moving forward.

SO if your API consumer is not a web browser, you most likely have nothing to do on API side regarding CORS. Other client don't make it a two step procedure by including an OPTIONS request.

3.Configuration line - http.cors() will add filter - org.springframework.web.filter.CorsFilter to your filter chain so place break points there & in your JwtAuthFilter to see where code flow is going.

4.System Behavior is expected to be different for urls - /token & /rest/** because token url is not secured while rest/** is allowed only for authenticated users so additional filters would come into picture.

Spring Security exclude url patterns in security annotation configurartion

How to disable spring security for particular url

So ideal way to find CORS issue is to debug your code by taking in problematic request & verifying that response header - Access-Control-Allow-Origin is populated correctly.