2

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'
    }
  }
];
Kenana Reda
  • 430
  • 1
  • 9
  • 24
  • You need to just check the existence of the session storage. Try to use location instead of router https://stackoverflow.com/questions/38186636/remove-a-parameter-from-queryparams-angular-2 – Samy Sammour Apr 28 '19 at 11:17

2 Answers2

1

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

Samy Sammour
  • 2,298
  • 2
  • 31
  • 66
  • Thanks for answering! I've just updated the question, plz have alook, I already save token to `localstorage` and in `CanActivate` there is 3 cases, first case, when authenticated previously, I just check if token still valid from its `expire_date`, the second case, when receive a new url token and there current registered one is not valid, so here return true , when return true, the token still in url! I can't use Fateh answer because I will enter a loop but my current code works fine except showing token in url – Kenana Reda Apr 28 '19 at 11:19
  • 1
    Solved :D Many Thanks! – Kenana Reda Apr 28 '19 at 12:46
0

you can remove you query params by there names, passing null value, if we suppose that your query parameter name is 'token'

this.router.navigate(
 ['login'], {
 queryParams: {
  token: null // pass null value to token delete it 
 },
 queryParamsHandling: 'merge'
})
Fateh Mohamed
  • 20,445
  • 5
  • 43
  • 52
  • it still enter a loop! and I don't need to remove parameter when navigate to login, i need to remove it when `auth` return true and user can navigate to home – Kenana Reda Apr 28 '19 at 07:20