The token was expected to have 3 parts, but got 4

Discussão em 'Angular' iniciado por Nathan, Novembro 7, 2024.

  1. Nathan

    Nathan Guest

    Tested with postman and everything works fine, so its frontend issue. My key for the token is the same as the one i put in angular as well.

    Also once i log in i receive an error with a GET request to a list of users when this works flawlessly in postman. But i don't know how relevant that is to this because we already know its the token.

    [​IMG]

    login.component.ts:

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { Router } from '@angular/router';
    import { AuthenticationService } from 'src/app/services/authentication.service';
    import { NotificationService } from 'src/app/services/notification.service';
    import { User } from 'src/app/model/user';
    import { Subscription } from 'rxjs';
    import { HttpResponse, HttpErrorResponse } from '@angular/common/http';
    import { NotificationType } from 'src/app/enum/notification-type.enum';
    // once the login.component.html is loaded, it will call this file
    @Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
    })
    export class LoginComponent implements OnInit, OnDestroy {
    public showLoading: boolean;

    private subscription: Subscription[]=[];

    constructor(private router: Router, private authenticationService: AuthenticationService
    ,private notificationService: NotificationService) { }

    ngOnInit(): void {
    if(this.authenticationService.isLoggedIn())
    {
    this.router.navigateByUrl("/user/management");
    }
    else
    {
    this.router.navigateByUrl("/login");
    }

    }
    public onLogin(user: User): void
    {
    this.showLoading = true;
    console.log(user);
    this.subscription.push(
    this.authenticationService.login(user).subscribe(
    (response: HttpResponse<User>) =>
    {
    const token = response.headers.get('Jwt-Token');
    this.authenticationService.saveToken(token);
    this.authenticationService.addUserToLocalCache(response.body);

    this.router.navigateByUrl("user/management");
    this.showLoading = false; // since were not at login page anymore
    },
    (errorResponse: HttpErrorResponse) =>
    {
    console.log(errorResponse);
    this.sendErrorNotification(NotificationType.ERROR,errorResponse.error.message);
    this.showLoading = false;
    }
    ));
    }
    private sendErrorNotification(notificationType: NotificationType, message: string): void {
    if(message)
    {
    this.notificationService.showNotification(notificationType,message);
    }
    else{
    this.notificationService.showNotification(notificationType,"An error occurred, please try again");

    }
    }

    ngOnDestroy(): void{
    this.subscription.forEach(sub=>sub.unsubscribe);
    }

    }


    authentication.service.ts:

    export class AuthenticationService {
    public host = environment.apiurl;
    private token: string;
    private LoggedInUsername: string;
    private jwtHelper = new JwtHelperService;

    constructor(private http: HttpClient) { }


    public login(user: User): Observable<HttpResponse<User> | HttpErrorResponse>
    {
    return this.http.post<User> (`${this.host}/user/login`,user,{observe: `response`});


    }
    public register(user: User): Observable<User | HttpErrorResponse>
    {
    return this.http.post<User | HttpErrorResponse>
    (`${this.host}/user/register`,user);
    }

    public logOut(): void
    {
    this.token = null;
    this.LoggedInUsername = null;
    localStorage.removeItem('user');
    localStorage.removeItem('token');
    localStorage.removeItem('users');
    }
    public saveToken(token: string): void
    {
    this.token = token;
    localStorage.setItem('token',token); // token: "spdinvps", so like key = 'token' value = token variable

    }
    public addUserToLocalCache(user: User): void
    {
    localStorage.setItem('token',JSON.stringify(user));
    }
    public getUserFromLocalCache(): User
    {
    return JSON.parse(localStorage.getItem('user'));
    }
    public loadToken(): void
    {
    this.token = localStorage.getItem('token');
    }
    public getToken(): string
    {
    return this.token;
    }
    // check to see if user is logged in or not
    public isLoggedIn(): boolean
    { this.loadToken(); // load token
    // if token isnt null or empty ill login, otherwise logout and return false
    if(this.token != null && this.token !=='')
    {
    // now we need to get make sure subject isnt null or empty
    if(this.jwtHelper.decodeToken(this.token).sub != null || '')
    if(!this.jwtHelper.isTokenExpired(this.token))
    {
    this.LoggedInUsername = this.jwtHelper.decodeToken(this.token).sub;
    }
    }
    else
    {
    this.logOut();
    return false;
    }
    }
    }


    environment.ts:

    export const environment = {
    production: false,
    apiurl: 'http://localhost:8480' // could put this in userservice put better to put it globally here
    };


    app.module.ts:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { AuthInterceptor } from './interceptor/auth.interceptor';
    import { NotificationModule } from './notification.module';
    import { LoginComponent } from './components/login/login.component';
    import { RegisterComponent } from './components/register/register.component';
    import { UserComponent } from './components/user/user.component';
    import { FormsModule } from '@angular/forms';


    @NgModule({
    declarations: [
    AppComponent,
    LoginComponent,
    RegisterComponent,
    UserComponent
    ],
    imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule,
    NotificationModule,

    ],
    providers: [
    {provide: HTTP_INTERCEPTORS,useClass: AuthInterceptor,multi:true}],
    bootstrap: [AppComponent]
    })
    export class AppModule { }


    auth.interceptor.ts:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {

    constructor( private authenticationService: AuthenticationService) {}

    intercept(httpRequest: HttpRequest<any>, httpHandler: HttpHandler): Observable<HttpEvent<any>> {

    if(httpRequest.url.includes(`${this.authenticationService.host}/user/login`))
    {
    return httpHandler.handle(httpRequest);
    }

    if(httpRequest.url.includes(`${this.authenticationService.host}/user/register`))
    {
    return httpHandler.handle(httpRequest);
    }
    if(httpRequest.url.includes(`${this.authenticationService.host}/user/resetpassword`))
    {
    return httpHandler.handle(httpRequest);
    }
    this.authenticationService.loadToken();
    const token = this.authenticationService.getToken();

    const request = httpRequest.clone({setHeaders: {Authorization: `Bearer ${token}`}});
    return httpHandler.handle(request);


    IntelliJ console log:

    com.auth0.jwt.exceptions.JWTDecodeException: The token was expected to have 3 parts, but got 4.
    at com.auth0.jwt.TokenUtils.splitToken(TokenUtils.java:21) ~[java-jwt-3.10.0.jar:3.10.0]
    at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:34) ~[java-jwt-3.10.0.jar:3.10.0]
    at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:246) ~[java-jwt-3.10.0.jar:3.10.0]
    at com.Bug_Tracker.utility.JWTTokenProvider.getSubject(JWTTokenProvider.java:59) ~[classes/:na]
    at com.Bug_Tracker.filter.JWTAuthorizationFilter.doFilterInternal(JWTAuthorizationFilter.java:45) ~[classes/:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
    at java.base/java.lang.Thread.run(Thread.java:830) ~[na:na]


    jwtfilter:

    @Component
    public class JWTAuthorizationFilter extends OncePerRequestFilter {
    private JWTTokenProvider jwtTokenProvider;
    public JWTAuthorizationFilter(JWTTokenProvider jwtTokenProvider) {
    this.jwtTokenProvider = jwtTokenProvider;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    if (request.getMethod().equalsIgnoreCase(SecurityConstant.OPTIONS_HTTP_METHOD)) // need to check if header structure is valid
    {
    response.setStatus(OK.value()); // if header is good then set it to 200 otherwise we need to get header
    } else
    {// call getHeader with HttpServletReq which gives me Bearer "token"
    String authorizationHeader = request.getHeader(AUTHORIZATION); // authheader = "Bearer token"
    if (authorizationHeader == null || !authorizationHeader.startsWith(SecurityConstant.TOKEN_PREFIX))
    {
    filterChain.doFilter(request, response);
    return;
    }
    String token = authorizationHeader.substring(SecurityConstant.TOKEN_PREFIX.length());
    String username = jwtTokenProvider.getSubject(token);
    if (jwtTokenProvider.isTokenValid(username, token) && SecurityContextHolder.getContext().getAuthentication() == null)
    {

    List<GrantedAuthority> authorities = jwtTokenProvider.getAuthorities(token); // get all authorities from that user

    Authentication authentication = jwtTokenProvider.getAuthentication(username, authorities, request);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    } else {
    SecurityContextHolder.clearContext();
    }
    }
    filterChain.doFilter(request, response);
    }
    }


    when i debug it and click login in angular app authorizationHeader is null:

    String authorizationHeader = request.getHeader(AUTHORIZATION);


    in my main file i have a cors-filter as well:

    @Bean
    public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
    corsConfiguration.setAllowedHeaders(Arrays.asList("Origin", "Access-Control-Allow-Origin", "Content-Type",
    "Accept", "Jwt-Token", "Authorization", "Origin, Accept", "X-Requested-With",
    "Access-Control-Request-Method", "Access-Control-Request-Headers"));
    corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Jwt-Token", "Authorization",
    "Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
    corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
    return new CorsFilter(urlBasedCorsConfigurationSource);
    }

    Continue reading...

Compartilhe esta Página