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'
}
}
];
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.
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