2

I don't know what's wrong, I checked online everywhere, it seems to be the same like I have but I am getting this issue:

I am requesting My Angular application using HttpClient with an Angular interceptor to setHeader because my Java Rest API is using JWT for authentication and needs a token in the header so it will fetch and verify the user request because the Angular interceptor is not working properly. I am getting null as token at the Java Side and getting an error. Please help me with this.

Finally I found its might be issue of spring security because i debug and found that option request all filter and its dont have header so its showing token and throw exceptions if option method request bypass and allow then might be my problem will solve

Spring boot Security Configuration

package com.techprimers.security.jwtsecurity.config;

import com.techprimers.security.jwtsecurity.security.JwtAuthenticationEntryPoint;
import com.techprimers.security.jwtsecurity.security.JwtAuthenticationProvider;
import com.techprimers.security.jwtsecurity.security.JwtAuthenticationTokenFilter;
import com.techprimers.security.jwtsecurity.security.JwtSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Collections;

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private JwtAuthenticationProvider authenticationProvider;
    @Autowired
    private JwtAuthenticationEntryPoint entryPoint;

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Collections.singletonList(authenticationProvider));
    }

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilter() {
        JwtAuthenticationTokenFilter filter = new JwtAuthenticationTokenFilter();
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationSuccessHandler(new JwtSuccessHandler());
        return filter;
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
                .authorizeRequests().antMatchers("**/rest/**").authenticated()
                .and()
                .exceptionHandling().authenticationEntryPoint(entryPoint)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        http.headers().cacheControl();



    }
}

Angular Interceptor Code

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available



            console.log("i am inside");

            request = request.clone({
                setHeaders: {
                    Accept: 'application/json',
                    Authorization: `Bearer ${localStorage.getItem('token')}`
                }
            });


        return next.handle(request);
    }
}

Angular Service

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ServiceService {

  constructor(private http: HttpClient) { }

  api_user_url = 'http://localhost:8095';

  getAllApiUsers(): Observable<any> {
    return this.http.get(this.api_user_url + "/allUser");
  }

  setUserLogin(obj):Observable<any>{

    return this.http.post(this.api_user_url +"/login", obj);
  }
}

CallIng Mathod

public getAllUserList() {

    console.log("I am calling");

    this.service.getAllApiUsers()
      .subscribe(data => {
        this.alluser = data;
        console.log(data);

      })
  }

Browser Network

Network Tab

Local Storage for Token

enter image description here

Browser Console Error Message

Browser Console

Spring Boot Java Console Error

backend Java Console Error

harkesh kumar
  • 833
  • 2
  • 13
  • 35
  • Is the token correctly available in localstorage? – user700284 Feb 27 '19 at 07:47
  • Where you register JwtInterceptor? It should be registered in app.module.ts. Add main module definition to your question too. You have a problem with cors, maybe you should deal with it first? – Krzysztof Raciniewski Feb 27 '19 at 07:49
  • @KrzysztofRaciniewski might be you asking about this------- providers: [ServiceService, { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true } ], – harkesh kumar Feb 27 '19 at 07:53
  • the screenshot of the network you share in your question is showing your method is `OPTION`. regarding the `OPTION` method visit this [link](https://stackoverflow.com/questions/36353532/angular2-options-method-sent-when-asking-for-http-get) but as per your console, you need to resolve the `cors` issue first. – Farhat Zaman Feb 27 '19 at 08:01
  • For the cors isue, try using http.cors instead of @CrossOrigin(origins = "*"). Make sure your authorization is being set by using developer tools network. The bearer and token is not visible in your screenshot. And I also see that you use the key 'token' to get the token in localstorage but key 'currentUser' is in localstorage. And putting your implementation of authenticationFilter may also help! – Merv Mar 05 '19 at 08:27

2 Answers2

1

I think the correct answer to your question is in the JwtSecurityConfig. you need to add the OPTIONS call to be permitted to pass the JWT security without requesting the auth token.

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable()
            .authorizeRequests()
            // Add this line to your code
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("**/rest/**").authenticated()
            .and()
            .exceptionHandling().authenticationEntryPoint(entryPoint)
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    http.headers().cacheControl();



}
You Rule Avi
  • 308
  • 1
  • 3
  • 8
0

Angular interceptor looks good but in your browser console there is CORS policy error. Your angular app is running on port 4200 and your backend is running on 8095(different hosts).

I don't know spring-boot but after reviewing the documentation you should add some cors policy to the backend application(different for production and development environment):

enter image description here

More you can read here: https://spring.io/guides/gs/rest-service-cors/

now your request to /allUser is not sent... After removing the CORS problem everything should work properly

Krzysztof Raciniewski
  • 4,735
  • 3
  • 21
  • 42
  • I Already applied like @CrossOrigin(origins = "*") @RestController – harkesh kumar Feb 28 '19 at 07:56
  • You're doing something wrong. Maybe read this: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework You should be able to send request to an unsecured controller/method(without JWT token) and the backend app should return response with code 200 - this is your priority, then deal with JWT authorization – Krzysztof Raciniewski Feb 28 '19 at 08:16
  • 1
    if i allow this url goes with token check then i will give me proper response becus it not adding token using interceptor so i am not getting token other side – harkesh kumar Feb 28 '19 at 08:20