Max
Max

Reputation: 21

CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource - Angular

I use Angular (localhost:4200) as my frontend and spring-boot (localhost:8080) as my backend.

my controller class is "/api/v1/admin"

When I send a get-request to get all the users in my database, i got an error.

I tried to request them as an admin and got a "No 'Access-Control-Allow-Origin' header is present on the requested resource" - error.

I have deducted the problem to my SecurityFilterChain:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

    httpSecurity
            .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();
}

when I got the ".requestMatchers("/api/v1/admin/**").hasAuthority("ADMIN")" i get the error.

but when I change that to ".requestMatchers("/api/v1/admin/**").permitAll()" it suddently works.

I dont want that "url" to be accessed by other roles, so I can't let it stay that way.

What can I do to prevent that error?

thx in advance!

I use Angular (localhost:4200) as my frontend and spring-boot (localhost:8080) as my backend.

my controller class is "/api/v1/admin"

When I send a get-request to get all the users in my database, i got an error.

I tried to request them as an admin and got a "No 'Access-Control-Allow-Origin' header is present on the requested resource" - error.

I have deducted the problem to my SecurityFilterChain:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

    httpSecurity
            .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();
}

when I got the ".requestMatchers("/api/v1/admin/**").hasAuthority("ADMIN")" i get the error.

but when I change that to ".requestMatchers("/api/v1/admin/**").permitAll()" it suddently works.

I dont want that "url" to be accessed by other roles, so I can't let it stay that way.

What can I do to prevent that error?

thx in advance!

EDIT 1

SecurityConfig class

@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;
    }
}

Controller class:

@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);
        }
    }
}

SOLUTION

It was quite easy, just hat to apply the cors filter to my http security, instead of disabling it^^

@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;
    }
}

hope it helps someone in the future :)

Upvotes: 0

Views: 554

Answers (1)

In your code, I don't see anything related to CORS. Remember that authorizeHttpRequests is used to exclude specific URLs from security, but not exclude it for CORS. Please try with the following modifications:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

    httpSecurity
        .cors().and()
        .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();

}

And after that, create the method:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration corsConfiguration=new CorsConfiguration();
    corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
    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;
}

In the line corsConfiguration.setAllowedOrigins(Arrays.asList("*"));, you will put your valid URLs.

Make sure the class has the following annotations: @Configuration and @EnableWebSecurity.

Upvotes: 0

Related Questions