Search code examples
angularangular-routerauth-guardquery-string

How to remove queryParams after navigation | Angular


I am using Angular application and trying to check in CanActivate if token is valid, if it's valid so return true. When true, I need to delete it from the url I've tried this code to delete the url param

let url: string = this.router.url.substring(0, this.router.url.indexOf("?")); this.router.navigateByUrl(url);

but it enters an endless loop. How to remove the params after using checking its validity?

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    let accesstoken: string = next.queryParams.accesstoken;
    if (this.authService.IsAuthenticated) {

      let user = this.authService.GetUser();
      let CurrentDate = new Date();
      let date = CurrentDate.getFullYear() + "-" + (CurrentDate.getMonth() + 1) + "-" + CurrentDate.getDate();

      if (Date.parse(date) <= Date.parse(user.expire_date)) {
        return true;
      }
    }
      else if (!NOU(accesstoken)) { // In case current registered token is not valid, CheckAccess with new token
        // this.authService.logout();
        this.authService.checkAccess(accesstoken).subscribe(
          data => {
            if (data === true) {
              return true;
            } else {
              this.router.navigate(['/login']);
              return false;
            }

          },
          error => {

          }
        );
      }
      else {
        this.router.navigate(['/login']);
        return false;
      }

  }

`

auth.service.ts

     checkAccess(accesstoken: string) {
    let Headers = new HttpHeaders();
    Headers = Headers.append('AuthenticationToken', accesstoken);
    return this.dataService
      .post<any>(`${this.authUrl}CheckAccess.json`, null, { headers: Headers })
      .pipe(
        map(response => {
          const authenticated = response.flag;
          // login successful
          if (authenticated) {
            // you can use  JSON.parse(localStorage.getItem('user')) statement to get the user information when needed.
            const user = new User(response);
            localStorage.setItem('user', JSON.stringify(user));
            localStorage.setItem('AuthenticationToken', accesstoken);
            this.IsAuthenticated = true;
            this.authenticationSource.next(true);
            // return true to indicate successful login
            return authenticated;
          }
        }),
        catchError(conError => {
          // return false to indicate failed login response 401
          return 'Failed';
        })
      );
  }

reverse-auth.guard.ts

    export class ReverseAuthGuard implements CanActivate {
  constructor(private router: Router, private authService: AuthService) { }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {

    if (this.authService.IsAuthenticated) {
      let user = this.authService.GetUser();
      let CurrentDate = new Date();
      let date = CurrentDate.getFullYear() + "-" + (CurrentDate.getMonth() + 1) + "-" + CurrentDate.getDate();

      if (Date.parse(date) > Date.parse(user.expire_date)) {
        // this.router.navigate(['/']);
        return true;
      }
      this.router.navigate(['/home']);
      return false;

    }
    else {
      return true;
    }

  }
}

app-routing.module.ts

   const routes: Routes = [
  {
    path: '',
    component: LayoutComponent,
    canActivate: [AuthGuard],
    children: [
      {
        path: 'home',
        loadChildren: './home/home.module#HomeModule',
        data: {
          title: 'Home'
        }
      },
      {
        path: '',
        redirectTo: 'home',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: 'unauthorized',
    component: UnauthorizedComponent,
    canActivate: [ReverseAuthGuard],
    data: {
      title: 'Unauthorized'
    }
  },
  {
    path: 'login',
    component: LoginComponent,
    canActivate: [ReverseAuthGuard],
    data: {
      title: 'Login'
    }
  }
];

Solution

  • You will go in an endless loop because you are always redirecting to the login and the login will check the token after you delete it which will do a redirect again.

    The solution for that is to save your token inside session storage:

    else if (!NOU(accesstoken)) {
         this.authService.checkAccess(accesstoken).subscribe(
           data => {
             if (data === true) {
               sessionStorage.setItem('access_token', accesstoken);
               return true;
             } else {
               const storageAccessToken = sessionStorage.getItem('access_token');
               if (storageAccessToken) {
                  return true;
               }
               this.router.navigate(['/login']);
               return false;
             }
          });
     } else {
        const storageAccessToken = sessionStorage.getItem('access_token');
        if (storageAccessToken) {
           return true;
        }
        this.router.navigate(['/login']);
        return false;
     }
    

    And you can then redirect with no problem. To delete it from you Url, there are many ways to do it as Fateh has mentioned in his answer.


    Edit:

    After your new edit for the answer, I realized that the problem with your code is redirecting when there is no token. So, a basic condition can solve the problem:

    if (this.authService.IsAuthenticated) {
    
      let user = this.authService.GetUser();
      let CurrentDate = new Date();
      let date = CurrentDate.getFullYear() + "-" + (CurrentDate.getMonth() + 1) + "-" + CurrentDate.getDate();
    
      if (Date.parse(date) <= Date.parse(user.expire_date)) {
        // check if accesstoken exists
        if (accesstoken) {
           // redirect only when exists
           this.router.navigateByUrl(window.location.pathname);
        }
        return true;
      }
    }
      else if (!NOU(accesstoken)) { // In case current registered token is not valid, CheckAccess with new token
        // this.authService.logout();
        this.authService.checkAccess(accesstoken).subscribe(
          data => {
            if (data === true) {
               // check if accesstoken exists
               if (accesstoken) {
                 // redirect only when exists
                 this.router.navigateByUrl(window.location.pathname);
               }
              return true;
            } else {
              this.router.navigate(['/login']);
              return false;
            }
    
          },
          error => {
    
          }
        );
      }
    

    Hope that answers your question