I want to redirect users who are not logged in when they try to access protected routes but redirection does not work because the function that checks if the user is logged in returns an Observable.
This is my code in PrivateGuard:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AmplifyService } from 'aws-amplify-angular';
@Injectable({
providedIn: 'root'
})
export class PrivateGuard implements CanActivate {
constructor (private _router: Router,
private _amplifyService: AmplifyService) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this._amplifyService.authStateChange$.pipe(map(authState => {
console.log(authState);
if (authState.state === 'signedIn') {
return true;
}else{
this._router.navigate(['/login']); // Why Never redirect?
return false;
}
})
);
}
}
app.routes.ts:
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './components/public/login/login.component';
import { HomeComponent } from './components/private/home/home.component';
const APP_ROUTES: Routes = [
{ path: 'login', component: LoginComponent},
{ path: 'home', component: HomeComponent, canActivate: [PrivateGuard] },
{ path: '**', pathMatch: 'full', redirectTo: 'home' }
];
export const APP_ROUTING = RouterModule.forRoot(APP_ROUTES);
If I write console.log in else statement when I'm logged in, this console.log appears in console, but never redirect to homeComponent
Console when I try navigate to a private route
The route in url dissapears, instead of localhost:4200/login
Thank you for any response.
SOLVED
Finally I use promise instead of observable. The code is the following:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AmplifyService } from 'aws-amplify-angular';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class PrivateGuard implements CanActivate {
constructor (private _router: Router,
private _amplifyService: AmplifyService) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this._amplifyService.auth().currentAuthenticatedUser()
.then(() => {
return true;
})
.catch(() => {
this._router.navigate(['/login']);
return false;
});
}
}
Thank you all for your answers
Your observable is probably never completing, it stills wait for authStateChange$ to emit more values.
You can achieve what you want by using the take operator (which will unsubscribe after one value emits :
return this._amplifyService.authStateChange$.pipe(
take(1), // completes the observable on first emited value
map(authState => /* */)
);