Problem retrieving JWT in Angular

Asked

Viewed 239 times

0

In the server-side I have a service using Spring Security and JWT for authentication and authorization, in the client-side I have a SPA in Angular. The problem occurs when I try to authenticate as I receive 200 as status code, but I cannot recover the token.

Spring

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
  private UserDetailsService userDetailsService;
  private BCryptPasswordEncoder bCryptPasswordEncoder;

public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
    this.userDetailsService = userDetailsService;
    this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
            .anyRequest().authenticated().and().addFilter(new JWTAuthenticationFilter(authenticationManager()))
            .addFilter(new JWTAuthorizationFilter(authenticationManager()))
            // this disables session creation on Spring Security
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
CorsConfigurationSource corsConfigurationSource() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addExposedHeader("Authorization");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("DELETE");
    source.registerCorsConfiguration("/**", config);
    return source;
}
}

Authenticationfilter

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;

public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

@Override
public Authentication attemptAuthentication(HttpServletRequest req,
                                            HttpServletResponse res) throws AuthenticationException {
    try {
        ApplicationUser creds = new ObjectMapper()
                .readValue(req.getInputStream(), ApplicationUser.class);

        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        creds.getUsername(),
                        creds.getPassword(),
                        new ArrayList<>())
        );
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

@Override
protected void successfulAuthentication(HttpServletRequest req,
                                        HttpServletResponse res,
                                        FilterChain chain,
                                        Authentication auth) throws IOException, ServletException {

    String token = Jwts.builder()
            .setSubject(((User) auth.getPrincipal()).getUsername())
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
            .signWith(SignatureAlgorithm.HS512, SECRET.getBytes())
            .compact();
    res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
}

}

Angular

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';

@Injectable()
  export class AuthService {

 private loggedIn = false;

 constructor(private http: HttpClient) {
    this.loggedIn = !!localStorage.getItem('auth-token');
 }

 login(username, password) {
    return this.http
     .post(
       'http://localhost:7070/login',
        { "username": username, "password": password }
        ).map((res: Response) => {
       console.log(res.headers.get('Authorization'));
      }) ;
 }
}

Console

Angular is running in the development mode. Call enableProdMode() to 
enable the production mode.
login.component.ts:28 TypeError: Cannot read property 'headers' of 
null
at MapSubscriber.eval [as project] (auth.service.ts:20)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:92)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:92)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:92)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)
at InnerSubscriber.Subscriber.next (Subscriber.js:92)

1 answer

1


Solution

Import the Httpresponse

import { HttpResponse } from '@angular/common/http';

Replace the class of Response for HttpResponse<any>

Modified method

login(username, password) {
return this.http
 .post(
   'http://localhost:7070/login',
    { "username": username, "password": password }
    ).map((res: HttpResponse<any>) => {
   console.log(res.headers.get('Authorization'));
  }) ;

}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.