I am receiving a null Authorization header when I am sending a request to a back-end controller designed with Spring Boot. But when I am sending the same request with Postman, the correct API is hit and data is properly fetched from the back-end.
On the Spring Boot side, here's the code for JwtSecurityConfiguration.java
:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "**/**").permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(entryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
I am receiving the null
authorization header in JwtAuthenticationToken.java
:
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
System.err.println("Header: " + header);
LOGGER.error("JWT Token is either missing from HTTP header or has been provided in an incorrect format!");
throw new AuthenticationCredentialsNotFoundException(
"JWT Token is either missing from HTTP header or has been provided in an incorrect format!");
}
String authenticationToken = header.substring(7);
JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(authenticationToken);
LOGGER.error("JWT Token has been received successfully. Authentication is in progress...");
return getAuthenticationManager().authenticate(jwtAuthenticationToken);
}
On the Angular side of the equation, I am using HTTP interceptors to add the JWT token to every request sent. Here's how my HttpInterceptorAuth.service.ts
looks:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let jwtAuthHeader = this._authSvc.getAuthorizedToken();
let jwtAuthUsername = this._authSvc.getLoggedInUsername();
if (jwtAuthHeader && jwtAuthUsername) {
request = request.clone({
setHeaders: {
Authorization: jwtAuthHeader
}
});
}
console.log(request);
return next.handle(request);
}
Since I'm logging the request sent by the HTTP interceptor, this is how it is in the Chrome console:
On the Network tab in Chrome Dev Tools, this is the request that's sent by Chrome:
Notice that the OPTIONS
request fails with 401 Unauthorized
.
This is probably because on the backend side, I am receiving an empty Authorization header when HTTP Interceptor has updated the request with the JWT Token in Authorization header.
I have no idea why the request that's actually sent is different from the one updated by HTTP interceptor. How can I solve this issue?
How do I avoid the preflight request check then?
You can not disable or avoid the Preflight request mechanism for CORS origins.
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own
To Resolve that you can use CorsConfigurationSource
or @CrossOrigin
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@CrossOrigin(origins = "*",allowCredentials = ,allowedHeaders = , exposedHeaders = , methods = , value = )
To Resolve that you can use in your controller the annotation:
@CrossOrigin (origins = "*" , exposedHeaders = "**")
Change * for your origin link, and ** for the specific token to expose.
Example:
@CrossOrigin(origins = "http://localhost:4200", exposedHeaders = "token")
@RestController
public class AuthenticationController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenService tokenService;
@PostMapping("/auth")
public ResponseEntity<?> autenticar(@RequestBody @Valid UserDTO userDTO){
UsernamePasswordAuthenticationToken userData = new UsernamePasswordAuthenticationToken(userDTO.getUserName(), userDTO.getPassword());
try {
Authentication authentication = authenticationManager.authenticate(userData);
String token = tokenService.generateToken(authentication);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("token", token);
return ResponseEntity.ok().headers(responseHeaders).build();
} catch (AuthenticationException e) {
return ResponseEntity.badRequest().build();
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.