I'm trying to add some custom headers in my angular interceptor as follow:
@Injectable()
export class HttpJwtAuthInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
localStorage.setItem('token', 'qsdfqsdfqsdfqsdf');
if (localStorage.getItem('cuid') && localStorage.getItem('token')) {
request = request.clone({
setHeaders: {
'sm_universalid':'blablabla',
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
}
return next.handle(request);
}
}
The above interceptor was added into providers property in app.module.ts:
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpJwtAuthInterceptor,
multi: true,
},
{ provide: BASE_PATH, useValue: environment.apiUrl },
],
In my spring boot application, I am adding a filter to check if the headers are received, if not it throw an exception:
String cuid = request.getHeader(SM_UNIVERSAL_ID);
if (cuid == null || cuid.isEmpty()) {
log.error("Failed authentication: cuid header not found in the request or it is empty");
throw new FailedAuthenticationException("cuid header not found in the request or it is empty:"+cuid);
}
Unfortunately the filter can't find the added headers, I tried to log the list of headers received and I found that they were added as value for access-control-request-headers header:
How can I get those headers separately? and why they were added into access-control-request-headers header?
Bellow a snapshot of my spring security class config (the header filter is applied there):
@Configuration
@EnableWebSecurity
@Slf4j
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final HeaderVerificationFilter headerVerificationFilter;
private final JwtAuthorizationFilter jwtAuthorizationFilter;
private final JwtAuthEntryPoint jwtAuthenticationEntryPoint;
@Override
protected void configure(HttpSecurity http) throws Exception {
//csrf is disabled because we are not using cookies
http.csrf().disable();
// No session will be created or used by spring security
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//Entry points
http.formLogin().loginProcessingUrl("/api/login").permitAll()
//Disallow everything else
.and().authorizeRequests().anyRequest().authenticated();
//if a user try to access a resource without having enough permissions
http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
// Apply Header and JWT filters
http.apply(new JwtTokenFilterConfigurer(headerVerificationFilter, jwtAuthorizationFilter, jwtAuthenticationEntryPoint));
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
@Override
public void configure(WebSecurity web) throws Exception {
// Allow swagger to be accessed without authentication
web.ignoring().antMatchers("/v2/api-docs")//
.antMatchers("/swagger-resources/**")//
.antMatchers("/swagger-ui.html")//
.antMatchers("/configuration/**")//
.antMatchers("/webjars/**")//
.antMatchers("/public");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return authenticationManager();
}
}
I don't know why, but I had to add my own custom CORS Policy config in my spring security config class, like that:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// allow requests
config.setAllowedOriginPatterns(List.of("*"));
//allowed methods
config.setAllowedMethods(Arrays.asList("POST", "OPTIONS", "GET", "DELETE", "PUT", "PATCH"));
// headers allow in request
config.setAllowedHeaders(
Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization"));
// headers exposed in response
config.setExposedHeaders(Arrays.asList("Token", "Authorization", "Content-Type", "Content-Disposition"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
And also, I had to permitt all method of type Options, like that:
@Override
protected void configure(HttpSecurity http) throws Exception {
//csrf is disabled because we are not using cookies
http.csrf().disable();
// No session will be created or used by spring security
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//Entry points
http.formLogin().loginProcessingUrl("/api/login").permitAll()
//Disallow everything else
.and().authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()//<-- this one
.anyRequest().authenticated();
//if a user try to access a resource without having enough permissions
http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
// Apply Header and JWT filters
http.apply(new JwtTokenFilterConfigurer(headerVerificationFilter, jwtAuthorizationFilter, jwtAuthenticationEntryPoint));
}