Reputation: 21
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
Reputation: 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